我正在尝试按每条记录的name
字段的字符对记录进行分组,并限制每组中的项目,这是我提出的内容:
desired_letters = ['a','b','c',..,'z']
some_variable = {}
for desired_letter in desired_letters:
some_variable += User.objects.all().order_by("name").filter(name__startswith=desired_letter)[:10]
我在for循环中运行此查询并将desired_letter
更改为我想要的字母,有没有其他方法可以优化此解决方案并使其成为单个查询而不是for循环?
答案 0 :(得分:12)
来自其他答案的评论:
我实际上是在寻找一种在django orm
中实现Group By First Character的方法
我会按照以下3个步骤进行:
使用name
字段的第一个字母为每条记录添加注释。为此,您可以使用Substr
函数以及Lower
from django.db.models.functions import Substr, Lower
qs = User.objects.annotate(fl_name=Lower(Substr('name', 1, 1)))
接下来,使用此第一个字母对所有记录进行分组,并获取ID的计数。这可以通过使用annotate with values:
来完成# since, we annotated each record we can use the first letter for grouping, and
# then get the count of ids for each group
from django.db.models import Count
qs = qs.values('fl_name').annotate(cnt_users=Count('id'))
接下来,您可以使用第一个字母订购此查询集:
qs = qs.order_by('fl_name')
将所有这些结合在一个陈述中:
from django.db.models.functions import Substr, Lower
from django.db.models import Count
qs = User.objects \
.annotate(fl_name=Lower(Substr('name', 1, 1))) \
.values('fl_name') \
.annotate(cnt_users=Count('id')) \
.order_by('fl_name')
最后,您的查询集看起来像这样。请注意,我在注释时将第一个字符转换为小写字母。如果您不需要,可以删除Lower
功能:
[{'fl_name': 'a', 'cnt_users': 12},
{'fl_name': 'b', 'cnt_users': 4},
...
...
{'fl_name': 'z', 'cnt_users': 3},]
如果,你需要一个字母和数字字典:
fl_count = dict(qs.values('fl_name', 'cnt_users'))
# {'a': 12, 'b': 4, ........., 'z': 3}
答案 1 :(得分:2)
首先排序然后过滤是过度的,徒劳无功。你应该只订购你需要的数据。否则,您按名称排序所有行 然后 过滤并切片所需的内容。
我愿意:
User.objects.filter(name__startswith=desired_letter).order_by("name")[:10]
和.all()
是多余的。
答案 2 :(得分:0)
对于Django REST,您可以参考,
Get Response Group by Alphabet
{
"A": [
"Adelanto",
"Azusa",
"Alameda",
"Albany",
"Alhambra",
"Anaheim"
],
"B": [
"Belmont",
"Berkeley",
"Beverly Hills",
"Big Sur",
"Burbank"
],
......
}