首页 > 解决方案 > 如何为使用相同 URL 的 GET 和 POST 请求设置不同的权限类?

问题描述

我正在使用 DRF(Django Rest Framework)构建端点。

django==2.1.5
djangorestframework==3.9.1
django-rest-auth
djangorestframework-jwt

我有模型“项目”,我想为 GET 和 POST 请求设置不同的权限类。

这是我的做法:

@csrf_exempt
@api_view(['GET', 'POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([AllowAny])
def item_list(request):
    if request.method == 'GET':
        items = Item.objects.all()
        serializer = ItemSerializer(items, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = ItemSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)

我想为所有方法使用一个端点,如下所示:

urlpatterns = [
    path('api/item/', views.item_list),
    path('api/item/<int:pk>/', views.item_details),
]

我想AllowAny用户GET请求方法并检查是否isAdminUser请求POST方法

我可以像在 Flask 中那样做吗,即一种方法的一种装饰器?

标签: pythondjangodjango-rest-framework

解决方案


由于您使用的是基于功能的视图,因此没有选项可以覆盖任何方法。您现在可以做的是,创建一个新的 Permission 类并将您的逻辑包含在其中

# permissions.py
from rest_framework.permissions import IsAdminUser


class MyCustomPermission(IsAdminUser):
    def has_permission(self, request, view):
        if request.method == 'GET':
            return True
        else:
            return super().has_permission(request, view)

并在您的视图中使用它,

# views.py
@csrf_exempt
@api_view(['GET', 'POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([MyCustomPermission]) # chage is here 
def item_list(request):
    if request.method == 'GET':
        items = Item.objects.all()
        serializer = ItemSerializer(items, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = ItemSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)


如果您计划迁移到基于类的视图,您可以通过覆盖该get_permissions()方法来实现。

你可以在这里找到一个简单的例子

def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    """
    if self.request.method == 'GET':
        permission_classes = [AllowAny]
    else:
        permission_classes = [IsAdminUser]
    return [permission() for permission in permission_classes]

推荐阅读