Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django rest framework error Cannot apply DjangoModelPermissions on a view that does not set `.queryset` or have a `.get_queryset()` method

i am using django 1.9.5 and rest framework 3.x(DRF).I have just following the tutorial from official django rest framework,you can say its getting start wiht DRF,i have write following views , urls to see how api works using DRF,

views

class DepartMentList(APIView):
    """
    List of all departments or create a department
    """

    def get(self, request, format=None):
        departments = Department.objects.all()
        serializer = DepartmentSerializer(departments)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = DepartmentSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()
            return   Response(serializer.data,status=status.HTTP_201_CREATED)
        return Response(serializer._errors, status=status.HTTP_400_BAD_REQUEST)

urls

from django.conf.urls import url

from rest_framework.urlpatterns import format_suffix_patterns

from organizations import views

    urlpatterns = [
        url(r'^departments/$', views.DepartMentList.as_view()),
    ]

    urlpatterns = format_suffix_patterns(urlpatterns)

and this is the setting.py where i have added the following rest framework dict for DEFAULT_PERMISSION_CLASSES

REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]

}

now when i run the endpoint for department to see the list of departments,then i am getting this following error,

'Cannot apply DjangoModelPermissions on a view that '
AssertionError: Cannot apply DjangoModelPermissions on a view that does not set `.queryset` or have a `.get_queryset()` method.

what does actually causes the error? i have investigated,but can't figure it out.

UPDATE

class DepartMentDetail(APIView):
    """
    Retrieve, update or delete a department instance.
    """

    def get_object(self, pk):

        try:
            return Department.objects.get(pk=pk)
        except Department.DoesNotExist:
            raise Http404

    def get(self,request,pk,format=None):

        department = self.get_object(pk)
        serializer = DepartmentSerializer(department)
        return Response(serializer.data)

    def put(self,request,pk,format=None):
        department = self.get_object(pk)
        serializer = DepartmentSerializer(department,data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        department = self.get_object(pk)
        department.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
like image 742
Md. Tanvir Raihan Avatar asked Apr 06 '16 05:04

Md. Tanvir Raihan


1 Answers

DjangoRestFramework requiries you to set queryset class argument or implement get_queryset method on your view. It checks it when applying permission class. Because DjangoModelPermissionsOrAnonReadOnly has has_permission method as shown below, and this method check if your view has queryset variable or get_queryset method.

def has_permission(self, request, view):
    # Workaround to ensure DjangoModelPermissions are not applied
    # to the root view when using DefaultRouter.
    if getattr(view, '_ignore_model_permissions', False):
        return True

    if hasattr(view, 'get_queryset'):
        queryset = view.get_queryset()
    else:
        queryset = getattr(view, 'queryset', None)

    assert queryset is not None, (
        'Cannot apply DjangoModelPermissions on a view that '
        'does not set `.queryset` or have a `.get_queryset()` method.'
    )

    perms = self.get_required_permissions(request.method, queryset.model)

    return (
        request.user and
        (request.user.is_authenticated() or not self.authenticated_users_only) and
        request.user.has_perms(perms)
    )

as you see has_permission method makes assert for queryset variable Your view should look like this

class DepartMentList(APIView):
    """
    List of all departments or create a department
    """
    queryset = Department.objects.all()

    def get(self, request, format=None):
        serializer = DepartmentSerializer(self.queryset)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = DepartmentSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()
            return   Response(serializer.data,status=status.HTTP_201_CREATED)
        return Response(serializer._errors, status=status.HTTP_400_BAD_REQUEST)

P.S use http://www.django-rest-framework.org/api-guide/generic-views/ it is much cleaner))

like image 59
Sardorbek Imomaliev Avatar answered Nov 20 '22 17:11

Sardorbek Imomaliev