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

时间:2016-05-21 09:55:52

标签: django database

我正在尝试按每条记录的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循环?

3 个答案:

答案 0 :(得分:12)

来自其他答案的评论:

  

我实际上是在寻找一种在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)))
    
  2. 接下来,使用此第一个字母对所有记录进行分组,并获取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'))
    
  3. 接下来,您可以使用第一个字母订购此查询集:

    qs = qs.order_by('fl_name')
    
  4. 将所有这些结合在一个陈述中:

    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"
    ],
    ......

}