我正在使用 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__'