【问题标题】:django rest framework error Cannot apply DjangoModelPermissions on a view that does not set `.queryset` or have a `.get_queryset()` methoddjango rest框架错误无法在没有设置`.queryset`或没有`.get_queryset()`方法的视图上应用DjangoModelPermissions
【发布时间】:2016-07-26 08:37:24
【问题描述】:

我正在使用 django 1.9.5 和 rest framework 3.x(DRF)。我刚刚按照官方 django rest framework 的教程进行操作,你可以说它是从 DRF 开始的,我写了以下 views , urls 查看 api 如何使用 DRF 工作,

观看次数

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)

网址

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)

这是我为 DEFAULT_PERMISSION_CLASSES 添加了以下 rest framework dict 的 setting.py

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'
]

}

现在当我为 department 运行 endpoint 以查看部门列表时,我收到以下错误,

'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.

究竟是什么导致了错误?我调查过,但无法弄清楚。

更新

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)

【问题讨论】:

标签: python django rest


【解决方案1】:

DjangoRestFramework 要求您在视图上设置queryset 类参数或实现get_queryset 方法。它在应用权限类时检查它。因为DjangoModelPermissionsOrAnonReadOnlyhas_permission方法如下图,这个方法检查你的view是有queryset变量还是get_queryset方法。

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)
    )

如您所见,has_permission 方法使 assert 成为 queryset 变量 您的视图应如下所示

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 使用http://www.django-rest-framework.org/api-guide/generic-views/ 更干净))

【讨论】:

  • 对不起,我要问你一个额外但相关的新手问题,我应该为我的detail view 做什么我在我的detail view 端点上遇到同样的错误,我只是忘了添加它顺便说一句,我在上面的帖子中做了什么,我使用get_object(self,pk) 来获取某些对象。我认为错误再次发生,我应该使用 get_queryset 而不是 get_object 吗? @Sardorbek Imomliev
  • @Rego 如果你想为你的部门模型制作完整的 CRUDL,你应该使用django-rest-framework.org/api-guide/viewsets。但如果您遇到同样的错误,您还需要提供queryset 类变量。
  • @Rego 你能在你的问题中添加get_object 实现吗?
  • @Rego 正如我之前所说,在使用 DjangoModelPermissionsOrAnonReadOnly 时,您必须提供 querysetget_quryset 它总是会检查它。但如果你愿意。您可以使用自定义 PrmessionClass 重新实现它
猜你喜欢
  • 2015-09-28
  • 2014-05-21
  • 2018-12-03
  • 2017-01-12
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 2018-08-12
  • 2020-10-06
相关资源
最近更新 更多