我正在编写一个复杂的django数据查询器并加快返回速度,我正在使用values()以及filter()和聚合,并且遇到了一些重复结果的问题。
像这样照片models.py
:
class Person(models.Model):
name= CharField()
class Question(models.Model):
title = CharField()
date_asked = DateField()
asker = ForeignKey(person)
我要做的是使用Person
查询集并使用values()
查询django以获取某人的姓名及其最新问题的标题。
如果我们有以下样本数据:
Person | Title | Date
----------------------------------------------
Jack | Where can I get water? | 2011-01-04
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
我可以通过这种方式获得大部分内容,例如:
人名列表最近问题的名称和日期:
Person.objects.values('name','most_recent')\\
.annotate('most_recent'=Max('question__date_asked'))
Person | most_recent
--------------------
Jack | 2012-02-05
Jill | 2014-03-06
人名列表及其所有问题及其标题:
Person.objects.values('name','question__title','question__date_asked')
Person | Title | Date
----------------------------------------------
Jack | Where can I get water? | 2011-01-04
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
但是当我尝试将它们放在一起时:
Person.objects.values('name','question__title','most_recent')\\
.annotate('most_recent'=Max('question__date_asked'))
.filt
Person | Title | most_recent
----------------------------------------------
Jack | Where can I get water? | 2011-01-04
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
即使使用F() expression也无法解决问题:
Person.objects.values('name','question__title','most_recent')\\
.annotate('most_recent'=Max('question__date_asked'))
.filter('question__date_asked'=F('most_recent'))
Person | Title | most_recent
----------------------------------------------
Jack | Where can I get water? | 2011-01-04
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
注意:在上表中,每个关系都给出了“最大”日期,而不是每个人。
我需要的是:
Person | Title | most_recent
----------------------------------------------
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
语句排序和连接中的某些内容意味着在同时使用过滤器,聚合和值时意味着连接发生在SQL USING语句之前,应该限制返回行
关于如何执行此查询的任何想法?
更新
相关的SQL查询如下所示:
SELECT "example_person"."full_name", "example_question"."title",
MAX("example_question"."date_asked") AS "max___example_question__date_asked"
FROM "example_person"
LEFT OUTER JOIN
"example_question" ON ( "example_person"."id" = "example_question"."person_id" )
INNER JOIN
"example_question" T3 ON ( "example_person"."id" = T3."person_id" )
GROUP BY
"example_person"."full_name", T3."start_date",
"example_person"."id", "example_question"."title"
HAVING
T3."date_asked" = (MAX("example_person"."date_asked"))
这个问题与djangos相比具有GROUP BY
语句的特异性。如果我运行./manage.py dbshell
并运行上面的查询,我会得到redundent结果,但如果我将其限制为GROUP BY "example_person"."full_name"
而没有其他分组,我会得到正确的结果。
有没有办法限制django的GROUP BY
或某种猴子补丁只是为了限制它?
答案 0 :(得分:0)
根据您的后端,您应该可以使用order_by
和distinct
完成此操作:
Question.objects.order_by('asker__name', '-date').distinct('asker__name')
这应该通过询问人的姓名和日期降序对您的对象进行排序,然后针对每个询问者提出第一个问题,这将是最新的问题。你没有提到你正在使用的后端,所以如果你使用像SQLite那样不支持不同的东西,你可能不得不以另一种方式这样做。
答案 1 :(得分:0)
这是我将更新的部分答案,但我找到了一种方法。
Django不喜欢你玩GROUP BY
语句而且他们被埋没了。 Waaaay很深。
然而,对于这个(仅限Django 1.7)猴子补丁,您可以覆盖分组的完成方式。在下面的例子中,我们捕获了你应该拥有的分组django think ,然后当且仅当此查询使用聚合时才将其删除(仅当有having_group_by
参数时才填充_get_grouping = SQLCompiler.get_grouping
def custom_get_grouping(compiler,having_group_by, ordering_group_by):
fields,thing = _get_grouping(compiler,having_group_by, ordering_group_by)
if having_group_by:
fields = fields[0:1]+[".".join(f) for f in having_group_by]
return fields,thing
SQLCompiler.get_grouping = custom_get_grouping
参数聚合
{{1}}
希望很快会有更好的方法......