From 92d30848db02a99f08699ac3d9a63c5b63b76930 Mon Sep 17 00:00:00 2001 From: acholyn Date: Tue, 24 Sep 2024 10:41:53 +0100 Subject: [PATCH] adding film manager to sort titles by number then alphabetically, ignoring the and a --- mod_app/models/film_model.py | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/mod_app/models/film_model.py b/mod_app/models/film_model.py index a654066c..de9d4cc9 100644 --- a/mod_app/models/film_model.py +++ b/mod_app/models/film_model.py @@ -1,5 +1,7 @@ from ckeditor_uploader.fields import RichTextUploadingField from django.db import models +from django.db.models import Case, When, Value, CharField +from django.db.models.functions import Substr, Lower, Trim from django.core.exceptions import ValidationError from django.urls import reverse @@ -15,6 +17,40 @@ def validate_format_other(value, format_type): raise ValidationError("Please provide format details; you've selected 'other' ") +class FilmManager(models.Manager): + def get_queryset(self): + """Order films first by number, then alphabetically, discarding prefix if they start with 'The' or 'A'""" + return ( + super() + .get_queryset() + .annotate( + # new field 'is_number' to check if the title starts with a number + is_number=Case( + When(title__regex=r"^\d", then=Value(0)), + default=Value(1), + output_field=models.IntegerField(), + ), + # annotate a field for sorting the title, ignoring "A " or "The " + sort_title=Case( + # starts with "The" + When( + title__iregex=r"^The\s+", + then=Lower(Trim(Substr("title", 5))), + ), + # starts with "A" + When( + title__iregex=r"^A\s+", + then=Lower(Trim(Substr("title", 3))), + ), + # then other titles + default=Lower(Trim("title")), + output_field=CharField(), + ), + ) + .order_by("is_number", "sort_title") + ) + + class Film(models.Model): def __str__(self): return f"{self.title}" @@ -22,6 +58,7 @@ def __str__(self): def get_absolute_url(self): return reverse("film_detail", kwargs={"pk": self.pk}) + objects = FilmManager() title = models.CharField(max_length=100) alt_titles = models.TextField( blank=True,