nin*_*nja 77 django django-queryset
我正在使用事务模型来跟踪通过系统的所有事件
class Transaction(models.Model):
actor = models.ForeignKey(User, related_name="actor")
acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
action_id = models.IntegerField()
......
Run Code Online (Sandbox Code Playgroud)
如何获得系统中的前5名演员?
在sql中它基本上是
SELECT actor, COUNT(*) as total
FROM Transaction
GROUP BY actor
ORDER BY total DESC
Run Code Online (Sandbox Code Playgroud)
Alv*_*aro 139
根据文档,您应该使用:
from django.db.models import Count
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
Run Code Online (Sandbox Code Playgroud)
values():指定将用于"分组依据"的列
Django文档:
"当使用values()子句约束结果集中返回的列时,用于评估注释的方法略有不同.原始结果根据原始QuerySet中的每个结果返回带注释的结果,而不是到values()子句中指定的字段的唯一组合"
annotate():指定对分组值的操作
Django文档:
生成汇总值的第二种方法是为QuerySet中的每个对象生成独立摘要.例如,如果您要检索书籍列表,您可能想知道有多少作者为每本书做出了贡献.每本书都与作者有多对多的关系; 我们想要总结QuerySet中每本书的这种关系.
可以使用annotate()子句生成每对象摘要.指定annotate()子句时,QuerySet中的每个对象都将使用指定的值进行批注.
order by子句是自解释的.
总结一下:你分组,生成一个作者的查询集,添加注释(这将为返回的值添加一个额外的字段),最后,你通过这个值对它们进行排序
有关更多信息,请参阅https://docs.djangoproject.com/en/dev/topics/db/aggregation/
Krz*_*iek 28
就像@Alvaro已经回答了Django的直接等同GROUP BY声明:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
Run Code Online (Sandbox Code Playgroud)
是通过使用values()和annotate()方法如下:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Run Code Online (Sandbox Code Playgroud)
如果模型具有定义的默认排序class Meta,则该.order_by()子句对于正确结果是强制性的.即使没有订购,您也无法跳过它.
此外,对于高质量的代码,建议始终.order_by()在后面添加一个子句annotate(),即使没有class Meta: ordering.这种方法将使声明具有前瞻性:它将按预期工作,无论将来有何变化class Meta: ordering.
我来举个例子.如果模型有:
class Transaction(models.Model):
actor = models.ForeignKey(User, related_name="actor")
acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
action_id = models.IntegerField()
class Meta:
ordering = ['id']
Run Code Online (Sandbox Code Playgroud)
然后这种方法不起作用:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Run Code Online (Sandbox Code Playgroud)
这是因为Django GROUP BY在每个领域都执行了额外的操作class Meta: ordering
如果要打印查询:
>>> print Transaction.objects.values('actor').annotate(total=Count('actor')).query
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
Run Code Online (Sandbox Code Playgroud)
很明显,聚合不会按预期工作,因此.order_by()必须使用该子句来清除此行为并获得正确的聚合结果.
请参阅:官方Django文档中与默认排序或order_by()的交互.
| 归档时间: |
|
| 查看次数: |
55525 次 |
| 最近记录: |