【问题标题】:Django - Annotate post query set data with if current user has "liked" the postDjango - 如果当前用户“喜欢”帖子,则注释帖子查询集数据
【发布时间】:2022-01-16 16:37:04
【问题描述】:

所以我有这个模型

model.py

class Post(models.Model):
    uuid = models.UUIDField(primary_key=True, default=generate_ulid_as_uuid, editable=False)
    created = models.DateTimeField('Created at', auto_now_add=True)
    updated_at = models.DateTimeField('Last updated at', auto_now=True, blank=True, null=True)
    creator = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="post_creator")
    body = models.CharField(max_length=POST_MAX_LEN, validators=[MinLengthValidator(POST_MIN_LEN)])

class LikePost(AbstractSimpleModel):
    creator = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="like_post")
    post = models.ForeignKey(Post)

class User(AbstractDatesModel):
    uuid = models.UUIDField(primary_key=True)
    username = models.CharField(max_length=USERNAME_MAX_LEN, unique=True, validators=[
        MinLengthValidator(USERNAME_MIN_LEN)])
    created = models.DateTimeField('Created at', auto_now_add=True)
    updated_at = models.DateTimeField('Last updated at', auto_now=True, blank=True, null=True)

然后我还有这个注释器,用于在 Post 表之外返回一堆数据

annotator.py

def query_to_full_post_data_serializer(post_query_set: QuerySet):
    query_set_annotated = post_query_set.annotate(
        creator_username=F('creator__username'),
        user_liked=F(<flag for each post in query for if user liked the post>)
        reply_count=Count('postreply', distinct=True),
        like_count=Count('likepost', distinct=True),
    ).prefetch_related(
        Prefetch('photo', Photo.objects.order_by('-created')),
        Prefetch('video', Video.objects.order_by('-created'))
    )
    return FullPostDataSerializer(query_set_annotated, many=True)

我想返回一个名为“user_liked”的字段,如果当前登录的用户喜欢它或者是@的creator,它会为查询集中的每个帖子返回一个布尔值,即True 987654327@ 到Post。当请求进来时,我让当前用户发出请求,这样我就可以得到他们的uuid。我想使用该 uuid 来检查用户是否喜欢查询集中的帖子。 如何检查当前登录的用户是否喜欢查询集 Django 中的 Post 对象?

我假设您可以执行 user_liked=F('likepost', filter=creator__uuid=current_user_uuid) 之类的操作,但这不会是返回用户的布尔值。如果我真的想要,我可以这样做 user_liked=Count('likepost, filter=creator__uuid=current_user_uuid) 不过似乎有点低效。

【问题讨论】:

    标签: python django


    【解决方案1】:

    对不起,我之前的错误答案。

    所以我对 Django ORM 相当生疏,因此查询可能没有最佳优化。这是我想出的

    Post.objects.all().annotate(liked_by_user=Q(likepost__creator=user))
    

    问题在于它会为找到的每个反向关系添加重复项。这就是为什么您不应该使用它并使用多对多的原因。

    例如,对于多对多,它会很简单

    class User2(models.Model):
        _id = models.BigAutoField(primary_key=True)
        
    
    class Post2(models.Model):
        _id = models.BigAutoField(primary_key=True)
        creators = models.ManyToManyField(User2)
    

    现在你只需要

    Post2.object.all().annotate(liked_by_user=Q(creator__in=[user]))
    

    哪个更好。

    【讨论】:

    • “添加重复项”是什么意思?我认为您正在编写的这些注释返回 LikePost 对象或它们的列表而不是布尔值,不是吗?我的理由是Q 用于查询,因此您实际上是在过滤LikePost,其中creator 等于某个uuid 或在uuid 列表中。
    • @user8714896 问题是对于每个帖子,可能有多个 LikePost,因此对于帖子的每个 LikePost,您将获得一个额外的行。因此,例如,您是否有喜欢帖子的 us1 和 us2,对于该帖子,您将有一个喜欢代表 us1,如果 us1 被记录,则为您提供 True,并且同一帖子的 us2 的附加行为您提供 False,所以您将不得不通过 groupby 和 big or 来组合线条
    • 您的帖子说不要使用多对多,然后您说“多对多就这么简单”,您能更明确一点吗?第一个多对多和第二个多对多指的不是很清楚。
    • 我在问题帖子中提出的过滤器然后计数解决方案是否涵盖了您所描述的问题?
    • 假设creatorpostLikePost 表中是唯一的,查询不会产生任何重复。尽管为了提高效率,最好使用Exists() subqueries。此外,@user8714896 可能有一些额外的多对多数据(因为它们继承自抽象模型),但他们应该将该模型指定为 through model
    猜你喜欢
    • 2020-11-04
    • 2019-08-12
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 2020-12-12
    • 2020-09-03
    相关资源
    最近更新 更多