繁体   English   中英

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"

我正在寻找一种“最佳做法”的方式来:

  • 获取所有博客
  • 为每个博客添加一个布尔值标志,指示我作为用户是否喜欢该帖子。

有效率的!

我的直觉使我想像这样实现它(使用基于类的通用视图)

// 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 )是否包含在喜欢的集合(如果BlogPost中)中。 你们知道我该如何实现吗?

谢谢

我可以想到两种方法来实现这一目标。

  1. 如果您只需要.extra boolean True / False无论request.user是否喜欢Post则可以使用.extra

    1.1。 将您的BlogPost Queryset 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') # ... 
  2. 获取整个BlogPostLike对象。

    2.1。更改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对象内添加一个新方法以返回此单个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 

您可以使用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})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM