【问题标题】:Django grouping queryset by first letter?Django按首字母分组查询集?
【发布时间】:2011-05-08 06:55:26
【问题描述】:

我有一个类似的查询集:

items = Item.objects.all()

项目有一个“名称”字段。在我要展示的模板中:

  • 一个
  • 酒精
  • B
  • 火箭筒
  • C
  • 硬币
  • 墨盒
  • S
  • 麻雀

因此项目按第一个字母排序和分组。缺少的字母被省略。有人有什么想法吗?

【问题讨论】:

    标签: django sorting django-templates


    【解决方案1】:

    如果您只关心它在页面上的显示,那么有一个模板标签。首先,在课堂上定义一个组织原则。在您的情况下,它是第一个字母:

    class Item(models.Model):
        ...
    
        def first_letter(self):
            return self.name and self.name[0] or ''
    

    然后在模板中定义一个重组,使用 first_letter 调用:

    {% regroup items by first_letter as letter_list %}
    <ul> 
    {% for letter in letter_list %}
      <li>{{ letter.grouper }}
        <ul>
            {% for item in letter.list %}
            <li>{{ item.name }}</li>
            {% endfor %}
        </ul>
      </li>
    {% endfor %}
    </ul>
    

    【讨论】:

    • 谢谢您,先生! :) 模型中的那个方法是我缺少的部分。
    • 解决问题的非常酷的方法。正在考虑将stackoverflow.com/questions/4151631/…djangosnippets.org/snippets/889 混合在一起@
    • 您不需要类上的方法,因为您可以在重组标记中使用过滤器。你可以做{% regroup items by name|first|upper as letter_list %}
    【解决方案2】:

    只是想补充一点,如果你使用它并且你的项目有一个小写的第一个字符,它将是一个单独的组。我在上面加上了。

    return self.name and self.name.upper()[0] or ''
    

    【讨论】:

      【解决方案3】:

      或者,您可以在模板中使用 slice 内联,而无需在模型上使用 first_letter 方法。

      {% regroup items by name|slice:":1" as letter_list %}
      <ul> 
      {% for letter in letter_list %}
        <li>{{ letter.grouper }}
          <ul>
              {% for item in letter.list %}
              <li>{{ item.name }}</li>
              {% endfor %}
          </ul>
        </li>
      {% endfor %}
      </ul>
      

      【讨论】:

      • 这个解决方案更好恕我直言
      【解决方案4】:

      更容易。您可以在“重新组合”中按第一个字母进行分组:

      {% regroup items|dictsort:"name" by name.0 as item_letter %}
      <ul>
      {% for letter in item_letter %}
          <h4>{{ letter.grouper|title }}</h4>
          {% for i in letter.list|dictsort:"name" %}
              <li>{{ i.name }}</li>
          {% endfor %}
      {% empty %}
          <span>There is no items yet...</span>
      {% endfor %}
      </ul>
      

      name.0 在这种情况下与 Python 中的 item.name[0] 相同。

      在 Django 1.10 中测试

      【讨论】:

        【解决方案5】:

        对于 Django REST,你可以这样做,

        import string
        import collections
        
        from rest_framework.response import Response
        from rest_framework import status, viewsets
        
        def groupby(self, request):
            result = []
            for i in list(string.ascii_uppercase):
                c = City.objects.filter(name__startswith=i)
                if c:
                    result.append((i, map((lambda x: x['name']),list(c.values('name')))
                    ))
            return Response(collections.OrderedDict(sorted(dict(result).items())), status=status.HTTP_200_OK)
        

        城市模型

        class City(models.Model):
            """All features model"""
        
            name = models.CharField(max_length=99)
        

        响应

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

        【讨论】:

        • 这太可怕了。你要进行 26 次查询...这不行。
        【解决方案6】:

        这是直接用 Django 和 Python 做的另一种方法。提供的另一种解决方案效率极低

        import itertools
        
        collector = {}
        item_qs = Item.objects.all().order_by('name')
        for alphabet_letter, items in itertools.groupby(item_qs, lambda x: x.name[0].lower()):
            # you can do any modifications you need at this point
            # you can do another loop if you want or a dictionary comprehension
            collector[alphabet_letter] = items  
        

        这给了你什么?对数据库的单个查询。

        我应该使用collector 吗?不,您也许应该使用 yield 这只是概念证明。

        无论您做什么,都在循环中添加查询调用。

        【讨论】:

        • 嗨,我知道我迟到了,但上面给了我一个“itertools._grouper 对象”,我不能使用,你能帮忙吗?
        • @shreyansh 当然可以。 itertools._grouper object 是另一个可迭代对象,注意循环有 alphabet_letteritemsitems 将是一个生成器,如果您需要多次访问它,您需要这样做:items = list(items) 在循环内。如果这些都没有帮助,请添加一个新问题并将其链接到此处,我会解决您的独特问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-18
        • 2014-10-24
        • 1970-01-01
        • 2014-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多