At s2k digital, we have various django models that have a field for state tracking. This could be a simple field with choices set, or when using django-fsm a so called FSMField, which is based on a CharField. An example models.py could look like this:

from django.db import models
from django_fsm import FSMField

class BlogPost(models.Model):
    STATE_CHOICES = (
        ("new", "new"),
        ("clearance", "in clearance"),
        ("correction", "correction requested"),
        ("done", "done"),
    )
    # Fields
    id = models.AutoField(primary_key=True)
    state = models.FSM(default="new", choices=STATE_CHOICES, blank=False, null=False)
    created_at = models.DateTimeField(auto_now_add=True)
    # some more very important fields
    
    class Meta:
        ordering = ["created_at"]

Most of the time, in addition to tracking state, these fields are also used for sorting. However, not always is it the lexicographic order of the fields’ values that should be used as the basis for sorting, but rather some custom order based on those values.

 

For example, in the above example, we would like to have the following order:

  1. correction
  2. clearance
  3. new
  4. done

Lets extend our models.py to reflect the desired ordering of states and add a custom manager BlogPostManager to our model:

class BlogPost(models.Model):
    STATE_CHOICES = (
        ("new", "new"),
        ("clearance", "in clearance"),
        ("correction", "correction requested"),
        ("done", "done"),
    )

    STATE_ORDERING = {
        "correction": 1,
        "clearance": 2,
        "new": 3,
        "done": 4,
    }

    ...
    ...

    objects = BlogPostManager()

    class Meta:
        # We want our BlogPosts to be ordered primarily according to
        # STATE_ORDERING, and secondarily by created_at
        ordering = ("created_at",)

In our custom BlogPostManager, we will then override the get_queryset method to return a queryset that is ordered according to STATE_ORDERING. We therefore have to annotate our queryset such that the included objects have an IntegerField called state_order, which is then used for ordering / sorting the queryset accordingly.

 

We can achieve all this by utilizing When and Case which are both provided by django.db.models. An example managers.py could look like this:

from django.db import models


class BlogPostManager(models.Manager):
    def get_queryset(self):
        qs = super().get_queryset()
        if qs.exists():
            state_ordering_pairs = self.model.STATE_ORDERING.items()
            whens = [
                models.When(schein__state=k, then=v) for k, v in state_ordering_pairs
            ]
            # annotate queryset with state_order 
            qs = qs.annotate(
                state_order=models.Case(
                    *whens, default=9999, output_field=models.IntegerField()
                )
            )
            # Make sure we apply the ordering specified in BlogPost's Meta class
            # after ordering by state_order
            ordering = ("state_order",) + self.model._meta.ordering
            qs = qs.order_by(*ordering)
        return qs

This will give us the desired ordering of our BlogPost objects. If you want to learn more about When and Case, you can read more about them in the Django documentation.
_

If you are looking for a Django related job, have feedback or questions, feel free to reach out to us on Twitter, LinkedIn or shoot us an email.

Also this year, s2k digital participated in DjangoCon Europe and had many interesting talks and conversations with other attendees. We would like to thank all participants and sponsors and especially the organizers of DjangoCon Europe, who made it possible for us to have a great event again this year.

 

We would like to positively highlight the talk by Rado Geogiev titled Quality Assurance in Django - Testing what matters and the talk by Bas Steins titled Deep Inside Django’s ORM: How Django Builds Queries.

 

Rado presented a testing approach that combines aspects of Integration Testing with aspects of Behaviour Driven Development (BDD) by simulating User Journeys while providing access to the internal state of the application. A look at the slides is definitely worthwhile.

 

Bas gave an insight into the internal architecture of the Django ORM in his talk, including some interesting details regarding the implementation of QuerySet and its related Methods, which could help to improve the understanding of how the Django ORM works under the hood.

 

We are eagerly awaiting the release of the videos and slides of the talks from DjangoCon Europe 2022 and are looking forward to DjangoCon US 2022, which will be held in San Diego in the USA from October 16-21.

_

If you are looking for a Django related job, have feedback or questions, feel free to reach out to us on Twitter, LinkedIn or shoot us an email.

s2k digital GmbH

We are digitalization experts facilitating the success of your digital transformation.

Digitalization Experts

Wuppertal / Bonn / Munich, Germany