Как использовать has_object_permission, чтобы проверить, может ли пользователь получить доступ к объекту в представлениях на основе функций

#python #django-rest-framework #django-permissions

#python #django-rest-framework #django-разрешения

Вопрос:

У меня есть объект note, к которому можно получить доступ из notes/{pk} . Если метод GET или метод только для чтения, я должен был разрешить любому доступ к заметке, если заметка общедоступна ( note.is_private = False )

Я реализовал это как:

 @api_view(['GET', 'DELETE', 'PUT'])
def detail_notes(request, pk): 
    try: 
        note = Note.objects.get(pk=pk)
    except Note.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET': 
        response = NoteSerializer(note)
        return Response(response.data)

...
 

Если метод УСТАНОВЛЕН или УДАЛЕН, я хочу разрешить доступ к заметке, только если текущий пользователь является владельцем заметки. Я реализовал это разрешение (согласно документам) следующим образом:

 class IsOwnerOrIsPublic(BasePermission):

    def has_object_permission(self, request, view, obj): 

        user = obj.user 
        privacy = obj.is_private

        if request.method in SAFE_METHODS:
            return not privacy # is the note public and is this a read only request ? 

        return request.user == obj.user
 

Однако, когда я добавляю @permission_classes([IsOwnerOrIsPublic]) декоратор в свое представление, разрешение не ограничивает доступ к неавторизованному пользователю. Я могу просмотреть любую заметку с помощью pk.

Я попытался явно вызвать IsOwnerOrIsPublic.has_object_permissions(), на мой взгляд, с этим кодом:

 authorized = IsOwnerOrIsPublic.has_object_permission(request, note)
    if not authorized:
        return Response(status=HTTP_401_UNAUTHORIZED)
 

Но я получаю ошибку has_object_permission() missing 2 required positional arguments: 'view' and 'obj' (очевидно), и я не знаю, какие еще аргументы передать. Например, что такое аргумент view?

Как мне заставить это разрешение работать с этим представлением? В качестве альтернативы, как мне заставить это ограничение работать?

Ответ №1:

Обратите внимание, что мое решение основано на общих представлениях, которые проще реализовать. Попробуйте использовать следующий класс представления:

 from rest_framework import generics
from django.shortcuts import get_object_or_404
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
...
# generics.RetrieveUpdateDestroyAPIView will allow Get, put, delete
class NoteDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
"""
Retrieve, update, or delete note by its author
Retrieve only for readers
"""
# I'll assume you are using token authentication
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated, IsOwnerOrIsPublic,)

serializer_class = NoteSerializer

def get_object(self):
    note = get_object_or_404(Note, pk=self.kwargs['pk'])
    self.check_object_permissions(self.request, note)
    return note