我查询一个模型:

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上做一些技巧,但我只是好奇如何不打补丁就能做到。


当前回答

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

results = Members.objects.raw('SELECT * FROM myapp_members GROUP BY designation')

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

query = Members.objects.all().query
query.group_by = ['designation']
results = QuerySet(query=query, model=Members)

现在可以遍历结果变量以检索结果。请注意,group_by没有文档,在Django的未来版本中可能会被更改。

和…为什么要使用group_by?如果不使用聚合,可以使用order_by来实现类似的结果。

其他回答

如果你想进行聚合,你可以使用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()的交互”的部分。

Django不支持自由分组查询。我是用一种非常糟糕的方式学会的。ORM不是设计来支持你想做的事情的,不使用自定义SQL。你被限制在:

RAW sql(即MyModel.objects.raw()) cr.执行句子(以及对结果的手工解析)。 .注解()(按句子分组在.注解()的子模型中执行,例如aggregating lines_count=Count('lines')))。

对于一个queryset,你可以调用qs.query。Group_by = ['field1', 'field2',…],但如果你不知道你在编辑什么查询,也不能保证它会工作,不会破坏QuerySet对象的内部结构,这是有风险的。此外,它是一个内部的(未被记录的)API,你不应该直接访问,否则会有代码与未来的Django版本不再兼容的风险。

还可以使用regroup模板标记按属性分组。从文档中可以看出:

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

<ul>
    {% for country in countries_list %}
        <li>{{ country.grouper }}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        </li>
    {% endfor %}
</ul>

看起来是这样的:

印度 孟买:19000000 加尔各答:15000000 美国 纽约:2000万 芝加哥:7000000 日本 东京:33000000

我相信它也适用于QuerySets。

来源:https://docs.djangoproject.com/en/2.1/ref/templates/builtins/重组

编辑:请注意,如果字典列表没有按键排序,regroup标记就不能正常工作。它是迭代工作的。因此,在将石斑鱼的键传递给regroup标记之前,对列表(或查询集)进行排序。

文档说您可以使用值来对查询集进行分组。

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

你可以找到所有的书,并按名字分组:

Book.objects.values('name').annotate(Count('id')).order_by() # ensure you add the order_by()

你可以在这里看一些小抄。

你需要做自定义SQL的例子在这段代码:

自定义SQL通过子查询

或者在Django在线文档中所示的自定义管理器中:

添加额外的Manager方法