Django按首字母分组查询集?

时间:2022-12-06 19:35:23

I have a QuerySet like:

我有一个QuerySet,如:

items = Item.objects.all()

Item has a 'name' field. In the template I want to show:

Item有一个'name'字段。在我想要显示的模板中:

  • A
  • 一个
  • Axes
  • Alcohol
  • B
  • Bazookas
  • 火箭筒
  • C
  • C
  • Coins
  • 硬币
  • Cartridges
  • 墨盒
  • S
  • 小号
  • Swords
  • Sparrows
  • 麻雀

So the items are ordered and group by the first letter. Missing letters are omitted. Does anyone have any ideas?

所以这些物品是按照第一个字母排序和分组的。遗漏的字母被省略。有没有人有任何想法?

5 个解决方案

#1


19  

There's a template tag for this, if all you care about is its presentation on the page. First, define an organizational principle in the class. In your case, it's the first letter:

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

class Item(models.Model):
    ...

    def first_letter(self):
        return self.name and self.name[0] or ''

And then define a regroup in the template, using the first_letter call:

然后使用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>

#2


6  

Just wanted to add that if you use this and your item has a lower-case first character it will be a separate group. I added upper to it.

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

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

#3


4  

Alternatively you could use slice inline in the template without the need for a first_letter method on your model.

或者,您可以在模板中使用切片内联,而无需在模型上使用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


1  

For Django REST you can do like this,

对于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)

City Models

class City(models.Model):
    """All features model"""

    name = models.CharField(max_length=99)

Response

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

}

#5


0  

Even easier. You can group by first leter just in 'regroup':

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

{% 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 in this case the same as item.name[0] in Python.

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

Tested in Django 1.10

在Django 1.10中测试过

#1


19  

There's a template tag for this, if all you care about is its presentation on the page. First, define an organizational principle in the class. In your case, it's the first letter:

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

class Item(models.Model):
    ...

    def first_letter(self):
        return self.name and self.name[0] or ''

And then define a regroup in the template, using the first_letter call:

然后使用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>

#2


6  

Just wanted to add that if you use this and your item has a lower-case first character it will be a separate group. I added upper to it.

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

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

#3


4  

Alternatively you could use slice inline in the template without the need for a first_letter method on your model.

或者,您可以在模板中使用切片内联,而无需在模型上使用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


1  

For Django REST you can do like this,

对于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)

City Models

class City(models.Model):
    """All features model"""

    name = models.CharField(max_length=99)

Response

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

}

#5


0  

Even easier. You can group by first leter just in 'regroup':

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

{% 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 in this case the same as item.name[0] in Python.

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

Tested in Django 1.10

在Django 1.10中测试过