Django查询集 - filter(),annotate()和values()

时间:2015-07-27 00:52:23

标签: python django

我正在编写一个复杂的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或某种猴子补丁只是为了限制它?

2 个答案:

答案 0 :(得分:0)

根据您的后端,您应该可以使用order_bydistinct完成此操作:

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}}

希望很快会有更好的方法......