Джанго группирует запрос по первой букве? - PullRequest
12 голосов
/ 11 ноября 2010

У меня есть QuerySet как:

items = Item.objects.all()

У элемента есть поле 'name'.В шаблоне я хочу показать:

  • A
  • Оси
  • Алкоголь
  • B
  • Базуки
  • C
  • Монеты
  • Патроны
  • S
  • Мечи
  • Воробьи

Итак предметыупорядочены и сгруппированы по первой букве.Отсутствующие буквы опущены.У кого-нибудь есть идеи?

Ответы [ 6 ]

19 голосов
/ 11 ноября 2010

Для этого есть тег шаблона, если все, что вас волнует, это его презентация на странице.Сначала определите организационный принцип в классе.В вашем случае это первая буква:

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>
6 голосов
/ 26 ноября 2012

Просто хотел добавить, что если вы используете это, и у вашего предмета есть первый символ в нижнем регистре, это будет отдельная группа.Я добавил верхний к этому.

return self.name and self.name.upper()[0] or ''
5 голосов
/ 25 мая 2014

В качестве альтернативы вы можете использовать slice inline в шаблоне без необходимости использования 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>
0 голосов
/ 12 октября 2018

Это еще один вариант для исполнения в 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, это просто подтверждение концепции.

Что бы вы ни делали, ДЕЛАЙТЕ НЕ добавление запроса в цикл.

0 голосов
/ 04 мая 2018

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

}
0 голосов
/ 19 октября 2016

Еще проще.Вы можете группировать по первому букве только в '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, в этом случае аналогично item.name[0] в Python.

Протестировано в Django 1.10

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...