2010-11-11 25 views
12

Tengo un QuerySet como:Django grouping queryset por primera letra?

items = Item.objects.all() 

El artículo tiene un campo 'nombre'. En la plantilla que quiero mostrar:

  • Un
  • ejes
  • alcohol
  • B
  • Bazookas
  • C
  • monedas
  • cartuchos
  • S
  • Swords
  • gorriones

Así que los artículos están clasificadas por grupo y la primera letra. Las letras perdidas se omiten. ¿Alguien tiene alguna idea?

Respuesta

19

Hay una etiqueta de plantilla para esto, si todo lo que le importa es su presentación en la página. Primero, defina un principio organizacional en la clase. En su caso, es la primera letra:

class Item(models.Model): 
    ... 

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

y luego definir un reagrupamiento en la plantilla, mediante la llamada 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> 
+0

Gracias, amable señor! :) Ese método dentro del modelo era mi parte faltante. – Tudorizer

+0

muy buena manera de resolver el problema. estaba buscando mezclar http://stackoverflow.com/questions/4151631/django-grouping-queryset-by-first-letter/4151742#4151742 y esto en conjunto https://djangosnippets.org/snippets/889/ –

+4

You don ' Necesito el método en la clase, ya que puede usar filtros en la etiqueta de reagrupación. Podrías hacer '{% reagrupar elementos por nombre | primero | superior como letter_list%}' –

6

sólo quería añadir que si se utiliza esta y su artículo tiene un primer carácter en minúsculas será un grupo separado. Añadí superior.

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

Como alternativa puede usar slice en línea en la plantilla sin la necesidad de un método first_letter en su modelo.

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

Esta solución es mejor en mi humilde opinión –

0

Aún más fácil. Puede agrupar por primera leter justo a 'reagrupar':

{% 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 en este caso el mismo que item.name[0] en Python.

Probado en Django 1.10

Cuestiones relacionadas