按外键/相关字段分组 django 查询集

Posted

技术标签:

【中文标题】按外键/相关字段分组 django 查询集【英文标题】:Group django queryset by foreign key / related field 【发布时间】:2014-01-18 01:59:58 【问题描述】:

考虑两个模型:

class Question(models.Model):
    ...

class Answer(models.Model):
    question = models.ForeignKey(Question)
    ...

目标是按问题对答案进行分组。我可以想到一些从Question 方面跨越模型关系的方法 - 检索所有有答案的问题:

Question.objects.annotate(answer_count = Count('answer')) \
                .filter(answer_count__gte=1)

然后我们可以遍历这个 QuerySet 并使用answer_set 来获得特定的答案。

这里的问题是,如果Question 表足够大,那么这个查询非常慢。在大多数问题都没有任何答案并且您最终用零注释一个巨大的表格的情况下,这更加难看。

如果从关系的另一端出发,并以某种方式将 Answer 实例按 question__id 字段分组,那就太好了。我现在的处理方式是:

answered_questions = [row['question'] for row in 
    Answer.objects.values('question').distinct('question')]
for question in answered_questions:
    answers = Answer.objects.filter(question__id=question)

这显然更快但也很笨拙。按外键对对象进行分组应该是一项非常常见的任务。有没有更好的方法?

【问题讨论】:

【参考方案1】:

您可以进行的最简单的查询是:

qs = Question.objects.annotate(answer_count = Count('answers')) \
            .filter(answer_count__gte=1).prefetch_related('answers')
# get answer list related to first question
print qs[0].answers.all()

假设你已经添加了related_name 属性:

class Answer(models.Model):
    question = models.ForeignKey(Question, related_name='answers')

我无法想象从数据库中获取所有问题的用例,您通常对数据进行分页之类的,因此查询速度慢应该不是问题。

【讨论】:

在大多数问题没有答案的情况下,我们获取大部分 Question 对象只是为了查看它们的answer_set 是空的,对吗?什么样的分页可以解决这个问题? 因此,如果问题的答案为零,您根本不想获取这些问题?关于分页,这取决于如何渲染数据,所以我们需要更多细节。 是的,我只想获取有一些答案的问题,如果问题不清楚,抱歉。我的 Django 应用程序仅对数据库进行查询并序列化数据以将其提供给客户端 javascript 进行渲染。 @martinthenext 我已经更新了我的答案,它基本上添加了您的过滤以避免空答案。关于分页,您可以通过添加?page=10 左右来简单地使用ajax 获取资源。使用ajax对数据进行分页的例子很多,请大家多多看看。

以上是关于按外键/相关字段分组 django 查询集的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 关系多对多按外键计数相关数据

Django过滤与其他模型的外键相关的模型的查询集?

如何通过django中的多级反向外键获取相关对象查询集?

按外键和日期分组数据,按日期汇总

如何在 BigQuery 中按外键分组?

需要在 Mongoose 中获取按外键分组的记录列表