Django (django-rest-framework) 寻找最佳实践来找出 request.user 是否存在于 blog.likes
Django (django-rest-framework) looking for a best practice to find out wether request.user exists in blog.likes
为简单起见,假设我在 Django (django-rest-framework) 应用程序中有以下模型。
User (id, name)
BlogPost (id, user, content, image)
BlogPostLikes(id, user, blogpost, timestamp)
// Assuming an inverse-relation to BlogPost via a variable called "likes"
我正在寻找一种 "best-practice" 的方式来:
- 获取所有博客
- 为每个博客添加一个布尔标志,指示我作为用户是否喜欢该博客 post。
高效!
我的直觉让我想像这样实现它(使用基于 class 的通用视图)
// views.py
class BlogPostList(ListAPIView):
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
def get(self, request, *args, **kwargs):
user = request.user
return super(BlogPostList, self).get(...)
// serializers.py
class BlogPostSerializer(serializer.ModelSerializer):
user = someUserSerializer(read_only=True)
likes = BlogPostLikesSerializer()
class Meta:
model = BlogPost
fields = ("id", "user", "likes", "content", "image")
class BlogPostLikesSerializer(serializer.ModelSerializer):
blogpost = BlogPostSerializer()
user = SomeUserSerializer()
class Meta:
model = BlogPostLikes
fields = ("id", "user", "blogpost", "timestamp")
但后来我卡住了。我不知道如何修改我的 BlogPostLikesSerializer
以指示当前用户(来自 views.py
的 request.user
)是否包含在博客帖子的点赞集中。你们知道我怎样才能做到这一点吗?
谢谢
您可以使用 SerializerMethodField 动态获取标志,如下所示:
class BlogPostSerializer(serializer.ModelSerializer):
user = SomeUserSerializer()
likes = BlogPostLikesSerializer()
has_liked = SerializerMethodField("get_has_liked")
class Meta:
model = BlogPostLikes
fields = ("id", "user", "likes", "content", "image", "has_liked")
def get_has_liked(self, obj):
user = self.context.get('request').user
return len([l.user.id == user.id for l in obj.likes]) > 0
但是,您需要在实例化序列化程序时传递请求,方法如下:serializer = BlogPostSerializer(context={'request': request})
我可以想到两种方法来实现这一点。
如果你只需要boolean
True
/False
是否Post
被request.user
喜欢,你可以使用 .extra
.
1.1。将您的 BlogPost
Queryset
更改为如下内容:
class BlogPostQuerySet(models.QuerySet):
def annotate_is_liked_by_user(self, user):
return self.extra(
select = {'is_liked': 'EXISTS( \
SELECT `id` FROM `blogpostlikes` \
WHERE `blogpostlikes`.`blogpost_id` = `blogpost`.id \
AND `blogpostlikes`.`user_id` = %s)' % user.id
}
)
class BlogPost
# other stuffs here
objects = BlogPostQuerySet.as_manager()
1.2。在 BlogPostList
视图
中更改 get_queryset
方法
class BlogPostList(ListAPIView):
def get_queryset(self):
user = self.request.user
return BlogPost.objects.annotate_is_liked_by_user(user)
1.3。将新字段添加到 BlogPostSerializer
class BlogPostSerializer(serializer.ModelSerializer):
# ....
is_liked = serializers.BooleanField(source='is_liked')
# ...
获取整个 BlogPostLike
对象。
2.1.Alter get_queryset
方法。
class BlogPostList(ListAPIView):
def get_queryset(self):
user = self.request.user
return BlogPost.objects.prefetch_related(
Prefetch(
'likes',
queryset=BlogPostLikes.objects.filter(user=user) \
.select_related('user'),
to_attr='likes_by_request_user'
)
)
2.2。改变 serializer
。但这可以通过两种方式完成:
2.2.1。序列化其中包含一项的列表:
class BlogPostSerializer(serializer.ModelSerializer):
# ...
likes_by_request_user = BlogPostLikesSerializer(many=True)
并从 BlogPostLikesSerializer
中删除 blogpost = BlogPostSerializer()
。我认为这会导致无限循环。
2.2.2 序列化单个对象:
class BlogPostSerializer(serializer.ModelSerializer):
# ...
like_by_request_user = BlogPostLikesSerializer(source='get_last_like', required=False)
但是这样你将不得不在你的 BlogPost
对象中添加一个新方法到 return 这个单一的 Like
对象
class BlogPost(models.Model):
#...
def get_last_like(self):
if hasattr(self, 'likes_by_request_user') and len(self.likes_by_request_user) > 0:
return self.likes_by_request_user[0]
return None
为简单起见,假设我在 Django (django-rest-framework) 应用程序中有以下模型。
User (id, name)
BlogPost (id, user, content, image)
BlogPostLikes(id, user, blogpost, timestamp)
// Assuming an inverse-relation to BlogPost via a variable called "likes"
我正在寻找一种 "best-practice" 的方式来:
- 获取所有博客
- 为每个博客添加一个布尔标志,指示我作为用户是否喜欢该博客 post。
高效!
我的直觉让我想像这样实现它(使用基于 class 的通用视图)
// views.py
class BlogPostList(ListAPIView):
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
def get(self, request, *args, **kwargs):
user = request.user
return super(BlogPostList, self).get(...)
// serializers.py
class BlogPostSerializer(serializer.ModelSerializer):
user = someUserSerializer(read_only=True)
likes = BlogPostLikesSerializer()
class Meta:
model = BlogPost
fields = ("id", "user", "likes", "content", "image")
class BlogPostLikesSerializer(serializer.ModelSerializer):
blogpost = BlogPostSerializer()
user = SomeUserSerializer()
class Meta:
model = BlogPostLikes
fields = ("id", "user", "blogpost", "timestamp")
但后来我卡住了。我不知道如何修改我的 BlogPostLikesSerializer
以指示当前用户(来自 views.py
的 request.user
)是否包含在博客帖子的点赞集中。你们知道我怎样才能做到这一点吗?
谢谢
您可以使用 SerializerMethodField 动态获取标志,如下所示:
class BlogPostSerializer(serializer.ModelSerializer):
user = SomeUserSerializer()
likes = BlogPostLikesSerializer()
has_liked = SerializerMethodField("get_has_liked")
class Meta:
model = BlogPostLikes
fields = ("id", "user", "likes", "content", "image", "has_liked")
def get_has_liked(self, obj):
user = self.context.get('request').user
return len([l.user.id == user.id for l in obj.likes]) > 0
但是,您需要在实例化序列化程序时传递请求,方法如下:serializer = BlogPostSerializer(context={'request': request})
我可以想到两种方法来实现这一点。
如果你只需要
boolean
True
/False
是否Post
被request.user
喜欢,你可以使用.extra
.1.1。将您的
BlogPost
Queryset
更改为如下内容:class BlogPostQuerySet(models.QuerySet): def annotate_is_liked_by_user(self, user): return self.extra( select = {'is_liked': 'EXISTS( \ SELECT `id` FROM `blogpostlikes` \ WHERE `blogpostlikes`.`blogpost_id` = `blogpost`.id \ AND `blogpostlikes`.`user_id` = %s)' % user.id } ) class BlogPost # other stuffs here objects = BlogPostQuerySet.as_manager()
1.2。在
中更改BlogPostList
视图get_queryset
方法class BlogPostList(ListAPIView): def get_queryset(self): user = self.request.user return BlogPost.objects.annotate_is_liked_by_user(user)
1.3。将新字段添加到
BlogPostSerializer
class BlogPostSerializer(serializer.ModelSerializer): # .... is_liked = serializers.BooleanField(source='is_liked') # ...
获取整个
BlogPostLike
对象。2.1.Alter
get_queryset
方法。class BlogPostList(ListAPIView): def get_queryset(self): user = self.request.user return BlogPost.objects.prefetch_related( Prefetch( 'likes', queryset=BlogPostLikes.objects.filter(user=user) \ .select_related('user'), to_attr='likes_by_request_user' ) )
2.2。改变
serializer
。但这可以通过两种方式完成:2.2.1。序列化其中包含一项的列表:
class BlogPostSerializer(serializer.ModelSerializer): # ... likes_by_request_user = BlogPostLikesSerializer(many=True)
并从
BlogPostLikesSerializer
中删除blogpost = BlogPostSerializer()
。我认为这会导致无限循环。2.2.2 序列化单个对象:
class BlogPostSerializer(serializer.ModelSerializer): # ... like_by_request_user = BlogPostLikesSerializer(source='get_last_like', required=False)
但是这样你将不得不在你的
BlogPost
对象中添加一个新方法到 return 这个单一的Like
对象class BlogPost(models.Model): #... def get_last_like(self): if hasattr(self, 'likes_by_request_user') and len(self.likes_by_request_user) > 0: return self.likes_by_request_user[0] return None