Question Django grouping queryset par première lettre?


J'ai un QuerySet comme:

items = Item.objects.all()

L'article a un champ "nom". Dans le modèle je veux montrer:

  • UNE
  • Les axes
  • De l'alcool
  • B
  • Bazookas
  • C
  • Pièces de monnaie
  • Cartouches
  • S
  • Épées
  • Moineaux

Ainsi, les articles sont classés et regroupés par la première lettre. Les lettres manquantes sont omises. Quelqu'un a-t-il une idée?


12
2017-11-11 05:35


origine


Réponses:


Il y a une balise de gabarit pour cela, si tout ce qui vous intéresse est sa présentation sur la page. Tout d'abord, définissez un principe d'organisation dans la classe. Dans votre cas, c'est la première lettre:

class Item(models.Model):
    ...

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

Et puis définissez un regroupement dans le template, en utilisant l'appel 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>

19
2017-11-11 05:57



Je voulais juste ajouter que si vous utilisez ceci et que votre objet a un premier caractère minuscule, ce sera un groupe séparé. J'ai ajouté le dessus.

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

6
2017-11-26 17:29



Sinon, vous pouvez utiliser slice inline dans le modèle sans la nécessité d'un first_letter méthode sur votre modèle.

{% 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>

5
2018-05-25 15:35



Pour Django REST, vous pouvez faire comme ça,

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)

Modèles de ville

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

    name = models.CharField(max_length=99)

Réponse

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

}

1
2018-05-04 06:09



Encore plus facile Vous pouvez grouper par premier compteur juste en 'regrouper':

{% 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 dans ce cas, le même que item.name[0] en Python.

Testé dans Django 1.10


0
2017-10-19 12:22