Home > Software engineering >  Django: Listing queryset results under alphabetical headings
Django: Listing queryset results under alphabetical headings

Time:12-10

I'm trying to list the results from a query of 'Articles' under alphabetical headings based of the Article Title, eg:

A

  • Apples
  • Anteaters

B

  • Bees
  • Bats

etc

I know I could do this manually with querysets and filters within the view but is there a more pythonic approach to this? My initial thought was a pair of for loops within the template, one with the alphabet and the other with the articles, with something like {% if article.startwith({{ letter}}) %} but I don't think that is included with the Django templating language.

Model:

class Article(models.Model):
title = models.CharField(max_length=200)
tagline = models.CharField(max_length=75, blank=False, default='Required')
author = models.ForeignKey(
    get_user_model(),
    on_delete=models.SET_NULL,
    null = True
    )
created = models.DateTimeField(auto_now_add=True)
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
tags = TaggableManager()
banner_image = models.ImageField(upload_to='wiki_images/banners', null=True, blank=True)
body = models.TextField()

I also considered the Django regroup tag but struggling to understand how to pass it the first letter of each articles title.

Running Django 3.1 on this project. edit: Typo

CodePudding user response:

Using regroup is a good idea!

But to have something to group on we also need to annotate our queryset with the first letter to have something to group on.

try this:

from django.db.models.functions import Substr, Upper

articles = Article.objects.annotate(first_letter=Upper(Substr('title', 1, 1)))

Then in template

{% regroup articles by first_letter as first_letter_articles %}
{% for first_letter in first_letter_articles %}
    <li>{{ first_letter.grouper }}
    <ul>
        {% for article in first_letter.list %}
          <li>{{ article.title }}</li>
        {% endfor %}
    </ul>
    </li>
{% endfor %}
  • Related