【问题标题】:Django group object by the first character of a columnDjango按列的第一个字符分组对象
【发布时间】:2016-09-18 14:04:52
【问题描述】:

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

【问题讨论】:

  • 好的,那我们有什么可以帮忙的呢?
  • @MosesKoledoye 我需要对此进行优化,并可能使用values() 函数将其作为单个查询
  • 这个 group by 没有任何意义吧?如果您按每个用户姓名的第一个字母进行分组,您只会得到 26 条记录,这就是您要查找的内容吗?

标签: django database


【解决方案1】:

对于 Django REST 你可以参考,

Get Response Group by Alphabet

响应

{
    "A": [
        "Adelanto",
        "Azusa",
        "Alameda",
        "Albany",
        "Alhambra",
        "Anaheim"
    ],
    "B": [
        "Belmont",
        "Berkeley",
        "Beverly Hills",
        "Big Sur",
        "Burbank"
    ],
    ......

}

【讨论】:

    【解决方案2】:

    来自另一个答案的评论:

    我实际上是在寻找一种在 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')
      

    将所有这些结合在一个语句中:

    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}
    

    【讨论】:

      【解决方案3】:

      先排序然后过滤是多余的,而且是徒劳的。你应该只订购你需要的数据。否则,您将按名称 对所有行进行排序,然后 过滤和切片您需要的内容。

      我愿意:

      User.objects.filter(name__startswith=desired_letter).order_by("name")[:10]
      

      .all() 是多余的。

      【讨论】:

      • 谢谢解答,分组怎么样,除了使用for循环还有其他方法吗?
      • 我已经编辑了这个问题,我实际上是在寻找一种在 django orm 中实现 this 的方法
      猜你喜欢
      • 2010-10-14
      • 2022-05-22
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      相关资源
      最近更新 更多