Python 如何在django中查询as GROUP BY?

Python 如何在django中查询as GROUP BY?,python,django,django-models,Python,Django,Django Models,我查询一个模型: Members.objects.all() 它返回: Eric, Salesman, X-Shop Freddie, Manager, X2-Shop Teddy, Salesman, X2-Shop Sean, Manager, X2-Shop 我想知道Django开火的最佳方式 对我的数据库的group\u by查询,如: Members.objects.all().group_by('designation') 当然,这是行不通的。 我知道我们可以在django/d

我查询一个模型:

Members.objects.all()
它返回:

Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2-Shop
Sean, Manager, X2-Shop
我想知道Django开火的最佳方式 对我的数据库的
group\u by
查询,如:

Members.objects.all().group_by('designation')
当然,这是行不通的。
我知道我们可以在
django/db/models/query.py上做一些技巧,但我只是想知道如何在不打补丁的情况下实现这些技巧。

您需要执行自定义SQL,如本文示例所示:

或者在自定义管理器中,如联机Django文档所示:


一个简单的解决方案,但不是正确的方法是使用:

另一种解决方案是使用
group_by
属性:

query = Members.objects.all().query
query.group_by = ['designation']
results = QuerySet(query=query, model=Members)
现在可以迭代results变量来检索结果。请注意,
group_by
未被记录,可能会在Django的未来版本中更改


而且。。。为什么要使用“分组依据”
?如果不使用聚合,可以使用
order\u by
来获得类似的结果。

如果要进行聚合,可以使用:

这将导致类似于的查询

SELECT designation, COUNT(designation) AS dcount
FROM members GROUP BY designation
输出的形式是

[{'designation': 'Salesman', 'dcount': 2}, 
 {'designation': 'Manager', 'dcount': 2}]
如果未包括
order\u by()
,如果默认排序不是您所期望的,则可能会得到不正确的结果

如果要在结果中包含多个字段,只需将它们作为参数添加到
值中即可,例如:

    .values('designation', 'first_name', 'last_name')
from django_group_by import GroupByMixin

class BookQuerySet(QuerySet, GroupByMixin):
    pass

class Book(Model):
    title = TextField(...)
    author = ForeignKey(User, ...)
    shop = ForeignKey(Shop, ...)
    price = DecimalField(...)
参考资料:
  • Django文档:,以及
  • Django文件:,特别是题为

Django不支持自由分组查询。我用一种非常糟糕的方式学的。ORM的设计目的不是为了在不使用自定义SQL的情况下支持您想要做的事情。您仅限于:

  • 原始sql(即MyModel.objects.RAW())
  • cr.execute
    语句(以及手工解析结果)
  • .annotate()
    (在聚合行数('line')等示例中,在.annotate()的子模型中执行按句子分组)

通过查询集
qs
可以调用
qs.query.group_by=['field1'、'field2'、…]
,但如果您不知道要编辑的查询是什么,并且无法保证它会工作并且不会破坏查询集对象的内部结构,那么这是有风险的。此外,它是一个内部(未记录的)API,您不应该直接访问它,否则代码将不再与未来的Django版本兼容。

以下模块允许您对Django模型进行分组,并在结果中使用QuerySet:

例如:

    .values('designation', 'first_name', 'last_name')
from django_group_by import GroupByMixin

class BookQuerySet(QuerySet, GroupByMixin):
    pass

class Book(Model):
    title = TextField(...)
    author = ForeignKey(User, ...)
    shop = ForeignKey(Shop, ...)
    price = DecimalField(...)

'book/books.html'

<ul>
{% for book in object_list %}
    <li>
        <h2>{{ book.title }}</td>
        <p>{{ book.author.last_name }}, {{ book.author.first_name }}</p>
        <p>{{ book.shop_count }}</p>
        <p>{{ book.price_avg }}</p>
    </li>
{% endfor %}
</ul>
注意:
ArrayAg
是一个特定于Postgres的函数,从Django 1.9开始提供:

说明可以使用值对查询集进行分组

class Travel(models.Model):
    interest = models.ForeignKey(Interest)
    user = models.ForeignKey(User)
    time = models.DateTimeField(auto_now_add=True)

# Find the travel and group by the interest:

>>> Travel.objects.values('interest').annotate(Count('user'))
<QuerySet [{'interest': 5, 'user__count': 2}, {'interest': 6, 'user__count': 1}]>
# the interest(id=5) had been visited for 2 times, 
# and the interest(id=6) had only been visited for 1 time.

>>> Travel.objects.values('interest').annotate(Count('user', distinct=True)) 
<QuerySet [{'interest': 5, 'user__count': 1}, {'interest': 6, 'user__count': 1}]>
# the interest(id=5) had been visited by only one person (but this person had 
#  visited the interest for 2 times

您可以观看一些cheet工作表。

您还可以使用
重新分组
模板标记按属性分组。从文档中:

cities = [
    {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
    {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
    {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
    {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
    {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]

...

{% regroup cities by country as country_list %}

<ul>
    {% for country in country_list %}
        <li>{{ country.grouper }}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        </li>
    {% endfor %}
</ul>
城市=[
{‘姓名’:‘孟买’,‘人口’:‘19000000’,‘国家’:‘印度’},
{‘姓名’:‘加尔各答’,‘人口’:‘15000000’,‘国家’:‘印度’},
{'name':'newyork','population':'20000000','country':'USA'},
{'name':'Chicago','population':'7000000','country':'USA'},
{‘姓名’:‘东京’,‘人口’:‘33000000’,‘国家’:‘日本’},
]
...
{%按国家/地区将城市重新组合为国家/地区列表%}
    {国家/地区中的国家/地区的%u列表%}
  • {{country.grouper}}
      {国家/地区中城市的百分比。列表%}
    • {{city.name}}:{{city.population}
    • {%endfor%}
  • {%endfor%}
看起来像这样:

  • 印度
    • 孟买:19000000
    • 加尔各答:1500万
  • 美国
    • 纽约:20000000
    • 芝加哥:700万
  • 日本
    • 东京:33000000
我相信它也适用于
QuerySet
s

资料来源:

编辑:请注意,如果字典列表未按键排序,则
regroup
标记的工作方式与预期不同。它以迭代方式工作。因此,在将列表(或查询集)传递给
regroup
标记之前,请按grouper的键对其进行排序

from django.db.models import Sum
Members.objects.annotate(total=Sum(designation))
首先,您需要导入Sum
然后..

换句话说,如果您只需要基于某个字段“删除重复项”,或者只需要查询ORM对象,我提出了以下解决方法:

from django.db.models import OuterRef, Exists

qs = Members.objects.all()
qs = qs.annotate(is_duplicate=Exists(
    Members.objects.filter(
        id__lt=OuterRef('id'),
        designation=OuterRef('designation')))
qs = qs.filter(is_duplicate=False)

因此,基本上,我们只是通过使用一些方便的筛选(根据您的型号和要求可能会有所不同)来注释
is\u duplicate
值,然后简单地使用该字段筛选出重复项。

您能告诉我如何使用order\u by??Hi,如果不使用聚合,则可以通过使用order_by来模拟group_,并消除不需要的条目。当然,这是一种模拟,只有在使用的数据不多时才可用。由于他没有提到聚合,我认为它可能是一个解决方案。嘿,这很好-你能解释一下如何使用execute_sql吗?它似乎不起作用。注意,这在Django 1.9上不再起作用。这是一种使用ORM的黑客方式。您不必手动实例化传递旧查询集的新查询集。这是一种往返解决方案。如果我能更广泛地使用它,我会用它的。但在这里,我只需要每个指定的成员数量,仅此而已。没问题。我本想提到1.1聚合功能,但假设您使用的是发行版:)这都是关于使用原始查询,这显示了Django的ORM的弱点。@Harry:您可以链接它。类似于:
Members.objects.filter(date=some\u date).values('designation').annotate(dcount=Count('designation'))
我有一个问题,这个查询只返回designation和dcount,如果我也想得到表的其他值怎么办?请注意,如果您的排序是一个字段而不是designation,那么它将无法与
cities = [
    {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
    {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
    {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
    {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
    {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]

...

{% regroup cities by country as country_list %}

<ul>
    {% for country in country_list %}
        <li>{{ country.grouper }}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        </li>
    {% endfor %}
</ul>
from django.db.models import Sum
Members.objects.annotate(total=Sum(designation))
from django.db.models import OuterRef, Exists

qs = Members.objects.all()
qs = qs.annotate(is_duplicate=Exists(
    Members.objects.filter(
        id__lt=OuterRef('id'),
        designation=OuterRef('designation')))
qs = qs.filter(is_duplicate=False)