Django组对象由列的第一个字符组成

sam*_*x73 7 database django

我正在尝试按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]
Run Code Online (Sandbox Code Playgroud)

我在for循环中运行此查询并更改desired_letter为我想要的字母,有没有其他方法来优化此解决方案并使其成为单个查询而不是for循环?

AKS*_*AKS 13

从其他答案中的评论:

我实际上是在寻找一种在django orm中实现Group By First Character的方法

我会按照以下3个步骤来做到这一点:

  1. 使用name字段的第一个字母注释每个记录.为此你可以使用Substr功能Lower

    from django.db.models.functions import Substr, Lower 
    qs = User.objects.annotate(fl_name=Lower(Substr('name', 1, 1)))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 接下来,使用此第一个字母对所有记录进行分组,并获取ID的计数.这可以通过使用值注释来完成:

    # 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'))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 接下来,您可以使用第一个字母订购此查询集:

    qs = qs.order_by('fl_name')
    
    Run Code Online (Sandbox Code Playgroud)

将所有这些结合在一个声明中:

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')
Run Code Online (Sandbox Code Playgroud)

最后,您的查询集看起来像这样.请注意,我在注释时将第一个字符转换为小写字母.如果您不需要,可以删除该Lower功能:

[{'fl_name': 'a', 'cnt_users': 12}, 
 {'fl_name': 'b', 'cnt_users': 4},
 ...
 ...
 {'fl_name': 'z', 'cnt_users': 3},]
Run Code Online (Sandbox Code Playgroud)

如果,你需要一个字母和计数字典:

fl_count = dict(qs.values('fl_name', 'cnt_users'))
# {'a': 12, 'b': 4, ........., 'z': 3}
Run Code Online (Sandbox Code Playgroud)