2014-04-22 34 views
9

我有这样的情况(实际代码绑定在模板中,为简洁起见省略)。Django的prefetch_related仅支持计数

threads = Thread.objects.all() 
for thread in threads: 
    print(thread.comments.count()) 
    print(thread.upvotes.count()) 

我设法大大减少了使用Django的真棒prefetch_related方法的查询总数。

threads = Thread.objects.prefetch_related('comments').prefetch_related('upvotes') 

但是,我想知道这种情况是否可以进一步优化。据我所知,prefetch_related检索所有与相关模型相关的数据。由于我只关心相关模型的数量,而不关心模型本身,因此似乎可以进一步优化此查询,以便它不检索大量不必要的数据。有没有办法在Django中做到这一点,而不会下降到原始SQL?

回答

11

你是对的,如果你想要做的就是获取数据,从数据库中获取所有数据是浪费的。我建议注释:

threads = (Thread.objects.annotate(Count('comments', distinct=True)) 
         .annotate(Count('upvotes', distinct=True))) 
for thread in threads: 
    print(thread.comments__count) 
    print(thread.upvotes__count) 

查看annotation documentation了解更多信息。

+0

太棒了,这正是我想要的,谢谢!同样通过Django的文档搜索,它看起来像1.7将能够实现类似于我所描述的使用新的Prefetch类和延迟未使用的字段的自定义查询集。但是,您的解决方案适用于Django的非流行版本。 – rectangletangle

+3

@rectangletangle:如果你关心的只是计数,注释仍然应该比'prefetch_related'更好。即使你推迟了除id之外的所有内容,当你可以为每个线程获取一个整数(count)时,没有理由为每个注释获取一个整数。 –

+0

这是一个好点。在这个和兼容性之间,我认为你有这个用例的优秀解决方案。 – rectangletangle