Как установить разные классы разрешений для запросов GET и POST, используя один и тот же URL?

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

Я создаю конечные точки с использованием DRF (Django Rest Framework).

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

У меня есть модель «Item», и я хочу установить разные классы разрешений для запросов 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, т. Е. Один декоратор для одного метода?

Ответ №1:

Поскольку вы используете представления на основе функций, нет возможности переопределять какие-либо методы. Что вы можете сделать сейчас, это создать новый класс разрешений и включить в него свою логику

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

Ответ №2:

Используйте представления на основе классов, определяйте и используйте пользовательские разрешения

Ответ №3:

Вы могли бы рассмотреть возможность определения двух отдельных функций с разными классами разрешений для «get» и «post».

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

@csrf_exempt
@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([isAdminUser])
def item_list_post(request):
    if 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)