我查询一个模型:
Members.objects.all()
它返回:
Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2-Shop
Sean, Manager, X2-Shop
我想要的是知道Django最好的点火方式
对我的数据库进行group_by查询,如:
Members.objects.all().group_by('designation')
当然,这是行不通的。
我知道我们可以在django/db/models/query.py上做一些技巧,但我只是好奇如何不打补丁就能做到。
如果你想进行聚合,你可以使用ORM的聚合特性:
from django.db.models import Count
result = (Members.objects
.values('designation')
.annotate(dcount=Count('designation'))
.order_by()
)
这将导致类似于
SELECT designation, COUNT(designation) AS dcount
FROM members GROUP BY designation
输出就是这样的形式
[{'designation': 'Salesman', 'dcount': 2},
{'designation': 'Manager', 'dcount': 2}]
如果不包括order_by(),如果默认排序不是您所期望的,则可能会得到不正确的结果。
如果你想在结果中包含多个字段,只需将它们作为参数添加到值中,例如:
.values('designation', 'first_name', 'last_name')
引用:
Django文档:values(), annotation()和Count
Django文档:聚合,特别是标题为“与默认排序或order_by()的交互”的部分。
换句话说,如果你只需要根据某些字段“删除重复项”,或者只是查询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_duplicate值,然后简单地使用该字段过滤掉重复项。
这有点复杂,但让提问者他/她期望只有一个DB命中。
from django.db.models import Subquery, OuterRef
member_qs = Members.objects.filter(
pk__in = Members.objects.values('designation').distinct().annotate(
pk = Subquery(
Members.objects.filter(
designation= OuterRef("designation")
)
.order_by("pk") # you can set other column, e.g. -pk, create_date...
.values("pk")[:1]
)
)
.values_list("pk", flat=True)
)
你也可以使用python内置的itertools。groupby直接:
from itertools import groupby
designation_key_func = lambda member: member.designation
queryset = Members.objects.all().select_related("designation")
for designation, member_group in groupby(queryset, designation_key_func):
print(f"{designation} : {list(member_group)}")
不需要原始sql、子查询、第三方库或模板标签,在我看来是python化的和显式的。