给出M个模型的N个相关模型

时间:2013-03-25 20:07:02

标签: sql django django-orm

鉴于两种模式:

class Post(models.Model):
   ...

class Comment(models.Model):
   post = models.ForeignKey(Post)
   ...

有没有一种方法可以在一组帖子上获得最后3条评论(即在一次往返数据包而不是每次发布一次)?一个天真的实现,以显示我的意思:

for post in Post.objects.filter(id__in=some_post_ids):
  post.latest_comments = list(Comment.objects.filter(post=post).order_by('-id')[:3])

鉴于some_post_ids == [1, 2],上述内容将导致3次查询:

[{'sql': 'SELECT "myapp_post"."id" FROM "myapp_post" WHERE "myapp_post"."id" IN (1, 2)', 'time': '0.001'},

{'sql': 'SELECT "myapp_comment"."id", "myapp_comment"."post_id" FROM "myapp_comment" WHERE "myapp_comment"."post_id" = 1  LIMIT 3', 'time': '0.001'},

{'sql': 'SELECT "myapp_comment"."id", "myapp_comment"."post_id" FROM "myapp_comment" WHERE "myapp_comment"."post_id" = 2  LIMIT 3', 'time': '0.001'}]

1 个答案:

答案 0 :(得分:1)

来自Django's docs

  

切片。如限制查询集中所述,可以使用Python的数组切片语法对QuerySet进行切片。切片未评估的QuerySet通常会返回另一个未评估的QuerySet,但如果使用切片语法的“step”参数,Django将执行数据库查询,并返回一个列表。切片已经评估过的QuerySet(部分或全部)也会返回一个列表。

您的天真实现是正确的,只应进行一次数据库查询。但是,不要在其上调用list,我相信这会导致数据库立即被命中(尽管它应该仍然只是一个查询)。它已经可迭代的查询集,实际上不应该需要调用list。有关从同一个文档页面调用list的更多信息:

  

列表()。通过调用list()来强制评估QuerySet。例如:   entry_list = list(Entry.objects.all())   但是要注意,这可能会产生很大的内存开销,因为Django会将列表中的每个元素加载到内存中。相反,迭代QuerySet将利用您的数据库加载数据并仅在您需要时实例化对象。

<强>更新

根据您添加的解释,我相信以下内容应该有效(但是,未经测试,请回报!):

post.latest_comments = Comment.objects.filter(post__in=some_post_ids).order_by('-id')

不可否认,它不会对每篇帖子发表3条评论的限制,我确信这是可能的,但我无法想到我的头脑中的语法。此外,请记住,您始终可以对任何模型进行手动查询以获得更好的优化,因此您可以运行Comment.query("Select ...;")

鉴于“从组中选择前N个”问题的here信息,如果你的IN条款将是少量的帖子,它可能只是更便宜a)做多个查询或b)选择帖子的所有评论然后在Python中过滤。如果每个帖子的评论数量相对较少,我建议使用if,如果它是少量帖子,那么每个帖子的评论相对较少。

相关问题