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中测试过