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)