【问题标题】:Django retrieve extra info using a single queryDjango 使用单个查询检索额外信息
【发布时间】:2015-05-21 17:26:47
【问题描述】:

我对这些模型有疑问:

class Post(models.Model):
    #Some fields ....


class LikePost(models.Model):
    # Author info
    author = models.ForeignKey(User,related_name='post_likes')
    post = models.ForeignKey(Post, related_name="likes")
    dateJoined = models.DateTimeField(auto_now_add=True)

当我检索帖子的信息时,我还需要知道当前用户 (request.user) 是否已经对当前帖子进行了likeAction。

当我获取帖子的详细信息时,我会使用单个查询来有效地(如果可能的话)。

目前我使用这个查询:

Post.objects.annotate(likes_count=Count('likes')).get(pk=pk)

我使用.annotate() 来检索点赞数...

我可以添加一些关于.annotate().extra() 的内容,以了解用户是否已经对当前帖子进行了likeAction?

【问题讨论】:

标签: python django django-orm


【解决方案1】:

这可能是个问题。

根据我的经验,Django ORM 最多只能将任何特定的表加入到一个查询中。这对于将多个条件应用于相同的相关数据很有用(这通常非常有用)。您需要的是一些相关数据的两个独立连接;一种是您计算所有喜欢,另一种是您只关心来自特定用户的喜欢。 Django 会做的是只计算特定用户的喜欢,如果你做了类似的事情

Posts.objects.filter(likes__user_id=user.id).annotate(
    likes_count=Count('likes')).get(pk=pk)

如果用户不喜欢特定的Post,您将面临DoesNotExist 异常的风险。如果用户确实喜欢特定帖子likes_count 将只计算特定用户和特定帖子之间的类似关系的数量。我相信这不是你需要的。

不过,您可以在一个查询中完成所有这些操作,但您会加载比其他方式所需的更多的数据;

post = Posts.objects.select_related('likes').get(pk=pk)
post.likes_count = len(post.likes)
user_already_likes_this = any(like.user_id == user.id for like in post.likes)

现在您必须对额外数据方法和两个查询方法进行基准测试。

我相信你应该只使用两个查询方法,因为每个 http 请求可能已经导致 15 个或更多查询,所以额外的一个不会造成太大的伤害,并且随着喜欢数量的增加它可以更好地扩展。

【讨论】:

    【解决方案2】:
    result = (Post.objects.annotate(likes_count=Count('likes'))
        .extra(
            select={
                'already_liked': (
                    "select count(*) from {app_name}_likepost "
                    "where {app_name}_likepost.author_id = {uid} "
                    "and {app_name}_likepost.post_id = {pid}"
                ).format(
                    uid=request.user.id,
                    pid=pk,
                    app_name=your_django_app_name,
                ),
            }
        )
        .get(pk=pk)
    )
    result.already_liked # 1 if action performed, 0 if not
    

    但是,这将是子查询,并且某些数据库可能不支持。 另外django docs 建议尽可能避免使用这种方法。虽然要在一个查询中获取所有需要的数据,但您需要这样做(或手动构建整个 sql 查询)。

    正如 django 文档所述,select_related 不适用于后向 foreign_key 关系,prefetch_related 实际上会再执行一次查询,因此总共将是两个查询(除此之外 - 它会加载很多更多不需要的数据,例如所有 LikePost 记录)。

    【讨论】:

      猜你喜欢
      • 2020-04-15
      • 2019-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-19
      • 1970-01-01
      • 2011-01-19
      • 1970-01-01
      相关资源
      最近更新 更多