Django: 分组吗?
我在寻找类似下面的东西:
previous_invoices = Invoice.objects.filter(is_open=False)
.order_by('-created')
.group_by('user')
但是 group_by()
这个功能不存在...
这个功能可以找到每个用户最近关闭的发票。
这个 聚合 API 似乎可以让你做一些关于计数和求和的操作,但我并不需要计数或求和,我实际上想要的是发票对象!
2 个回答
这里有一篇来自2007年的文章,讲的是如何在Django中实现这个功能,但其实在1.1版本之前,Django就已经有一个不太公开的`group_by`功能了。不过,一年前的这个讨论似乎提供了一些有用的信息。简单来说:
Django故意不在它的ORM(对象关系映射)中直接提供“GROUP BY”这样的功能。虽然我们使用的是关系型数据库,有时候会有一些相关的特性显露出来,但ORM的接口设计上是和SQL无关的。相反,我们提供了一些特定的功能,这些功能在转换成SQL时可能会用到“GROUP BY”,但实际上它们也可以通过其他完全不同的方式来实现,甚至可以用不同的存储系统来完成。
另外,文中提到使用extra
,以及它可能出现的各种问题。祝你好运!
选项 1:
虽然 Django 中没有 group_by()
这个功能,但你可以通过使用 latest()
方法来获取每个用户最近关闭的发票,同时也可以根据用户进行筛选:
previous_invoices = Invoice.objects.filter(user=my_user, is_open=False)
.latest('created')
对于旧版本的 Django,如果没有 latest()
,查询的写法会是这样的:
previous_invoices = Invoice.objects.filter(user=my_user, is_open=False)
.order_by('-created')[0]
选项 2:
更新:我在这里添加了一个问答风格的例子:如何在 Django ORM 中执行 GROUP BY ... COUNT 或 SUM?,这个例子展示了如何在 Django ORM 中模拟 GROUP BY
操作。
如果你真的想要实现 group_by
的效果,可以手动创建一个,具体方法可以参考这里的接受答案:Django 按字段值分组。
使用
.values_list()
并设置flat=True
,这样可以获取数据库中现有值的列表(如果你事先不知道这些值)。同时使用.distinct()
来去除重复值,因为我们不需要这些重复的:value_list = MyModel.objects.values_list( 'interesting_field', flat=True ).distinct()
现在遍历
value_list
,并填充你的字典:group_by_value = {} for value in value_list: group_by_value[value] = MyModel.objects.filter(interesting_field=value)
现在
group_by_value
字典的键是你interesting_field
中的不同值,而值是查询集对象,每个对象包含MyModel
中与interesting_field=a value from value_list
相对应的条目。
注意:
有一个库叫做 django-group-by,它声称可以在 Django 中添加 group_by()
功能,你可以去看看。