Python Django查询集-filter()、annotate()和values()
我正在编写一个复杂的django数据查询程序,为了加快返回速度,我将与filter()和aggregate一起使用,并且在重复结果方面遇到了一些问题 图片aPython Django查询集-filter()、annotate()和values(),python,django,Python,Django,我正在编写一个复杂的django数据查询程序,为了加快返回速度,我将与filter()和aggregate一起使用,并且在重复结果方面遇到了一些问题 图片amodels.py如下所示: class Person(models.Model): name= CharField() class Question(models.Model): title = CharField() date_asked = DateField() asker = ForeignKey(
models.py
如下所示:
class Person(models.Model):
name= CharField()
class Question(models.Model):
title = CharField()
date_asked = DateField()
asker = ForeignKey(person)
我要做的是使用person
queryset和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
即使使用A也不能解决问题:
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语句之前,该语句应该限制返回行
关于如何执行此查询,有什么想法吗
更新:
Person | Title | most_recent
----------------------------------------------
Jack | How to climb hill? | 2012-02-05
Jill | How to fix head injury? | 2014-03-06
相关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"))
Question.objects.order_by('asker__name', '-date').distinct('asker__name')
djangos对GROUP BY
语句的特异性过于敏感。如果我运行/manage.py dbshell
并运行上面的查询,我会得到redundent结果,但是如果我将其限制为按“示例人员”分组。“全名”
,没有其他分组,我会得到正确的结果
有没有办法限制django的
分组方式
或某种猴子补丁,只是稍微限制一下?根据您的后端,您应该能够通过命令和不同的
来实现这一点,如下所示:
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"))
Question.objects.order_by('asker__name', '-date').distinct('asker__name')
这应该按照提问者的姓名和日期降序排列对象,然后为每个提问者回答第一个问题,这将是最新的问题。您没有提到您正在使用的后端,因此如果您使用的是像SQLite这样不支持distinct的东西,您可能需要用另一种方法来实现这一点。这是我将更新的部分答案,但我找到了一种方法
Django不喜欢你玩groupby
语句,它们被隐藏得很深。瓦艾深
不过,使用这个(仅适用于Django 1.7)monkey修补程序,您可以覆盖分组的方式。在下面的示例中,我们捕获django认为您应该拥有的分组,然后在且仅当此查询使用聚合时将其缩减(只有在存在聚合时才会填充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
希望很快会有更好的方法……您是否尝试添加distinct()
?在这里可以找到类似的问题,但这些答案可能不令人满意。这是一个难题。@RetoAebersolddistinct
不起作用,因为它返回不同的行。我看不到你的人和问题模型之间有任何关系。@Burnkhalid eek…修复了现在由于太复杂的原因,我需要使用t他Person
queryset,而不是问题queryset