Django: 分组吗?

4 投票
2 回答
2289 浏览
提问于 2025-04-15 20:22

我在寻找类似下面的东西:

previous_invoices = Invoice.objects.filter(is_open=False)
                                   .order_by('-created')
                                   .group_by('user')

但是 group_by() 这个功能不存在...

这个功能可以找到每个用户最近关闭的发票。

这个 聚合 API 似乎可以让你做一些关于计数和求和的操作,但我并不需要计数或求和,我实际上想要的是发票对象!

2 个回答

2

这里有一篇来自2007年的文章,讲的是如何在Django中实现这个功能,但其实在1.1版本之前,Django就已经有一个不太公开的`group_by`功能了。不过,一年前的这个讨论似乎提供了一些有用的信息。简单来说:

Django故意不在它的ORM(对象关系映射)中直接提供“GROUP BY”这样的功能。虽然我们使用的是关系型数据库,有时候会有一些相关的特性显露出来,但ORM的接口设计上是和SQL无关的。相反,我们提供了一些特定的功能,这些功能在转换成SQL时可能会用到“GROUP BY”,但实际上它们也可以通过其他完全不同的方式来实现,甚至可以用不同的存储系统来完成。

另外,文中提到使用extra,以及它可能出现的各种问题。祝你好运!

2

选项 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 按字段值分组

  1. 使用 .values_list() 并设置 flat=True,这样可以获取数据库中现有值的列表(如果你事先不知道这些值)。同时使用 .distinct() 来去除重复值,因为我们不需要这些重复的:

    value_list = MyModel.objects.values_list(
        'interesting_field', flat=True
    ).distinct()
    
  2. 现在遍历 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() 功能,你可以去看看。

撰写回答