Django ORM:检索帖子和最新评论而不执行 N+1 查询

2024-05-26

我有一个非常标准的基本社交应用程序 - 具有状态更新(即帖子)和每个帖子的多个评论。

给定以下简化模型,是否可以使用 Django 的 ORM 高效检索所有帖子以及最新两条评论与每个帖子关联,而不执行 N+1 查询? (也就是说,无需执行单独的查询来获取页面上每个帖子的最新评论。)

class Post(models.Model):
    title = models.CharField(max_length=255)
    text = models.TextField()

class Comment(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, related_name='comments')

    class Meta:
        ordering = ['-pk']

Post.objects.prefetch_related('comments').all()获取所有帖子和评论,但我只想检索每个帖子的有限数量的评论。

UPDATE:

我明白,如果这可以使用 Django 的 ORM 来完成,那么可能必须使用某些版本来完成prefetch_related。多个查询完全没问题,只要我避免每页进行 N+1 次查询即可。

在 Django 中处理这个问题的典型/推荐方法是什么?

更新2:

似乎没有直接且简单的方法可以通过使用 Django ORM 的简单查询来有效地完成此操作。下面的答案中有许多有用的解决方案/方法/解决方法,包括:

  • 在数据库中缓存最新的评论ID
  • 执行原始 SQL 查询
  • 检索所有评论 ID 并在 python 中进行分组和“加入”
  • 限制您的应用程序仅显示最新评论

我不知道应该将哪一个标记为正确,因为我还没有机会尝试所有这些方法,但我向 hynekcer 提供了赏金,因为它提供了多种选择。

更新3:

我最终使用了@user1583799的解决方案。


如果您使用的是 Django 1.7 新版本Prefetch https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related对象(允许您自定义预取查询集)可能会很有帮助。

不幸的是,我想不出一种简单的方法来完全满足您的要求。如果您使用 PostgreSQL 并且愿意只获取每篇文章的最新评论,则以下内容应该适用于两个查询:

comments = Comment.objects.order_by('post_id', '-id').distinct('post_id')
posts = Post.objects.prefetch_related(Prefetch('comments',
                                               queryset=comments,
                                               to_attr='latest_comments'))

for post in posts:
    latest_comment = post.latest_comments[0] if post.latest_comments else None

另一种变体:如果您的评论有时间戳,并且您想将评论限制为按日期显示的最新评论,则看起来像:

comments = Comment.objects.filter(timestamp__gt=one_day_ago)

...然后如上所述。当然,您仍然可以对结果列表进行后处理,以将显示限制为最多两条评论。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django ORM:检索帖子和最新评论而不执行 N+1 查询 的相关文章

随机推荐