Как остановить появление связанного ресурса в представлении в django rest framework - PullRequest
0 голосов
/ 20 апреля 2020

Я проделал некоторую работу, следуя учебнику по django. Я хотел бы добавить возможность сделать фрагмент частным, чтобы другие пользователи его не увидели. Я создал дополнительное поле для фрагмента и попытался реализовать это с помощью прав доступа к объектам. Он работает так, что другие пользователи не видят его в подробном представлении (403 запрещено), и после переопределения метода list в ViewSet для его фильтрации он больше там не отображается. Тем не менее, он по-прежнему указан в разделе пользователя, поскольку это связанное поле.

Как отфильтровать его из представления пользователя, чтобы API возвращал только ресурсы, которые может видеть текущий пользователь.

У меня есть models.py вот так:

class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    ...
    private = models.BooleanField(default=False)

serializers.py:

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    highlight = serializers.HyperlinkedIdentityField(
        view_name='snippet-highlight', format='html')

    class Meta:
        model = Snippet
        fields = ('url', 'id', 'highlight', 'owner', 'title', 'code',
                  'linenos', 'language', 'style', 'private')

class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = serializers.HyperlinkedRelatedField(
        many=True, view_name='snippet-detail', read_only=True)

    class Meta:
        model = User
        fields = ('url', 'id', 'username', 'snippets')

views.py:

class SnippetViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.

    Additionally we also provide an extra `highlight` action.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (
        permissions.IsAuthenticatedOrReadOnly,
        SeeSnippet, )

    def list(self, request):
        queryset = Snippet.objects.filter(Q(owner=self.request.user) | Q(private=False))
        serializer = SnippetSerializer(queryset, many=True, 
                                       context={'request': self.request})
        return Response(serializer.data)

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

permissions.py:

class SeeSnippet(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # If the object is private, then check if the user is the owner.
        # Reject if not as non-owners should not be able to see it.
        if obj.private:
            return obj.owner == request.user

        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user

1 Ответ

1 голос
/ 20 апреля 2020

Документы DRF упоминают об этом ограничении своих разрешений на уровне объектов в документах . Таким образом, лучший способ справиться с этим - отредактировать набор запросов в представлении списка, чтобы имитировать c функциональность ваших разрешений. Другой вариант - использовать фреймворк, такой как django -guardian , хотя он довольно сложный.

...