如何在django中避免n + 1选择?

时间:2011-06-17 16:16:20

标签: django orm join

我有一个非常简单的数据模型,视频和评论之间有一对多的关系

class Video(models.Model):
    url = models.URLField(unique=True)
    .....

class Comment(models.Model):
    title = models.CharField(max_length=128)
    video = models.ForeignKey('Video')
        .....

我想查询视频并抓取整个对象图(包含所有评论的视频)。看看sql,我看到它有两个选择,一个用于视频,一个用于评论。我该如何避免?我想加入并立即抓住所有内容。

用django可以做到这一点吗?

3 个答案:

答案 0 :(得分:12)

对于ForeignKey,您可以使用selected_related()

Comment.objects.select_related('video').all()

它只会生成一个查询,为您和视频收集内容。

对于更复杂的东西(例如M2M),您需要一个外部应用程序(如unjoinify)来进行优化,但它使用SQL查询然后将它们放回到对象中。

如果你对此不感兴趣(我是),你有一些选择:

答案 1 :(得分:1)

您需要做的是在评论中使用select_related。

让我们说你需要找到标题以“The”开头的所有视频以及与之相关的评论

comments = Comment.objects.filter(video__title__starts_with='The')
           .select_related('video').all()

这将加载该评论的所有评论和相应的视频对象。您仍需要透过视频来迭代视频。使用python itertools.groupby函数在内存中进行旋转。

答案 2 :(得分:0)

看看select related是否按照预期的方式工作,它就是为此而制作的。