Фильтр связанных объектов в сериализаторе DRF на основе разрешений пользователя

Я работаю с Django Rest Framework и мне нужно фильтровать связанные объекты в сериализаторе на основе пользовательских прав. В частности, я хочу условно включать или исключать определенные связанные объекты (в данном случае комментарии) в сериализованный ответ в зависимости от отношения пользователя к первичному объекту (записи в блоге).

Например, пользователь должен видеть все комментарии, если он обладает особыми правами (например, является владельцем или назначенным сотрудником в блоге). В противном случае они должны видеть только те комментарии, которые соответствуют определенным критериям (например, одобренные комментарии).

Я придумал это решение, но я не уверен, что это самый эффективный подход. Как мне следует решить эту проблему?

# models.py
from django.db import models
from django.contrib.auth.models import User

class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    owner = models.ForeignKey(User, related_name="owned_posts", on_delete=models.CASCADE)
    writers = models.ManyToManyField(User, related_name="written_posts")

class Comment(models.Model):
    post = models.ForeignKey(Blog, related_name="comments", on_delete=models.CASCADE)
    approved = models.BooleanField(default=False)
    text = models.TextField()
# serializers.py
from rest_framework import serializers

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

class BlogSerializer(serializers.ModelSerializer):
    comments = serializers.SerializerMethodField()

    class Meta:
        model = Blog
        fields = '__all__'

    def get_comments(self, obj):
        user = self.context['request'].user
        if obj.owner == user or user in obj.writers.all():
            # Show all comments if the user is the owner or a writer
            comments = obj.comments.all()
        else:
            # Otherwise, show only approved comments
            comments = obj.comments.filter(approved=True)
        return CommentSerializer(comments, many=True).data
# views.py

class BlogViewSet(viewsets.ModelViewSet):
    serializer_class = BlogSerializer
    permission_classes = (MainModelPermissions,)
    pagination_class = LimitOffsetPagination
    allowed_methods = ("list", "retrieve")

    def get_queryset(self):
        return Blog.objects.all()

Вы можете работать с Prefetch объектом [Django-doc]:

from django.db.models import Q


class BlogViewSet(viewsets.ModelViewSet):
    # …
    def get_queryset(self):
        queryset = Blog.objects.prefetch_related(
            Prefetch(
                'comments',
                Comment.objects.filter(
                    Q(post__author=self.request.user) | Q(approved=True)
                ),
            )
        )

Таким образом, Comment будет сохраняться только в том случае, если approved=True или , если post__author, автор сообщения этого комментария, является зарегистрированным пользователем (request.user).

и все. Сериализатору не нужно беспокоиться о том, какие комментарии извлекать:

class BlogSerializer(serializers.ModelSerializer):
    comments = serializer.CommentSerializer(many=True)

    class Meta:
        model = Blog
        fields = '__all__'
Вернуться на верх