首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django querysets filter()、annotate()和value()

Django querysets filter()、annotate()和value()
EN

Stack Overflow用户
提问于 2015-07-27 00:52:22
回答 2查看 959关注 0票数 2

我正在编写一个复杂的django数据查询程序,为了加快返回速度,我使用了值()以及filter()和聚合,并且存在一些重复结果的问题。

想象一下这样的models.py

代码语言:javascript
复制
class Person(models.Model):
    name= CharField()

class Question(models.Model):
    title = CharField()
    date_asked = DateField()
    asker = ForeignKey(person)

我想要做的是查询django,使用Person查询集和使用values()来获取一个人的名字和他们最近问题的标题。

如果我们有以下示例数据:

代码语言:javascript
复制
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

我可以这样做,就像这样:

最近问题的民族名单、姓名和日期:

代码语言:javascript
复制
Person.objects.values('name','most_recent')\\
              .annotate('most_recent'=Max('question__date_asked'))

Person | most_recent
--------------------
Jack   | 2012-02-05
Jill   | 2014-03-06

人民名单、姓名及其所有问题和标题:

代码语言:javascript
复制
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

但当我试着把它们放在一起时:

代码语言:javascript
复制
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()表达式也不能解决问题:

代码语言:javascript
复制
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

注:在上表中,给出了每个关系的最大日期,而不是每个人的最大日期。

我需要的是:

代码语言:javascript
复制
Person | Title                    | most_recent
----------------------------------------------
Jack   | How to climb hill?       | 2012-02-05
Jill   | How to fix head injury?  | 2014-03-06

语句和联接的排序意味着,当使用筛选器、聚合和值时,同时意味着联接发生在SQL the语句之前,语句应该限制返回行。

关于我如何执行这个查询,有什么想法吗?

更新:

相关的SQL查询如下所示:

代码语言:javascript
复制
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并运行上面的查询,就会得到冗余的结果,但是如果我将其限制为GROUP BY "example_person"."full_name"而没有其他分组,我就会得到正确的结果。

有没有办法限制django的GROUP BY或者某种猴子补丁来限制它呢?

EN

回答 2

Stack Overflow用户

发布于 2015-07-27 15:52:06

根据后端的不同,您应该能够使用这样的order_bydistinct来完成这一任务:

代码语言:javascript
复制
Question.objects.order_by('asker__name', '-date').distinct('asker__name')

这应该按照被问者的姓名和日期进行排序,然后为每个被问者接受第一个问题,这将是最新的问题。您没有提到您正在使用的后端,所以如果您使用的是像SQLite这样的不支持不同的东西,那么您可能不得不用另一种方法。

票数 1
EN

Stack Overflow用户

发布于 2015-07-27 23:26:02

这是一个部分的答案,我会更新,但我找到了一个方法。

Django不喜欢你玩GROUP BY语句,它们被埋得很深。太深了。

但是,使用这个(只使用Django 1.7 )的猴子补丁,您可以覆盖分组是如何完成的。在下面的示例中,我们捕获了django认为您应该拥有的分组,然后将其剪回当且仅当该查询使用聚合(只有在存在聚合时才填充having_group_by参数。

代码语言:javascript
复制
_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

希望很快会有更好的办法..。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31643558

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档