Query results, finely ordered

Django's QuerySet API allows you to express the concept of the “latest” and “earliest” instance from a set. What does “latest” mean for your data? Django can't guess, so you need to specify that:

from django.db import models

class Subscription(models.Model):
    """ A subscription to our magazine. """

    created = models.DateField(auto_now_add=True)
    renewed = models.DateField(null=True)
    next_reminder = models.DateField()
    expires = models.DateField()
    email_address = models.EmailField()
>>> latest_subscription = Subscription.objects.latest('renewed')
>>> latest_subscription.email_address
'michele58@barton-bird.biz'

When it makes sense for a model to have a default “latest” definition, you use the get_latest_by option on the model:

from django.db import models

class Subscription(models.Model):
    """ A subscription to our magazine. """

    created = models.DateField(auto_now_add=True)
    renewed = models.DateField(null=True)
    next_reminder = models.DateField()
    expires = models.DateField()
    email_address = models.EmailField()

    class Meta:
        get_latest_by = 'renewed'

That allows you to omit the field name to the latest call, to use the default definition:

>>> latest_subscription = Subscription.objects.latest()
>>> latest_subscription.email_address
'michele58@barton-bird.biz'

Latest instance, by multiple fields

When a specified field has duplicate values, this gives ambiguous results when asking to order by that field. To solve this, the QuerySet API allows multiple fields in the order_by call:

>>> Subscription.objects.order_by('renewed', '-next_reminder', 'expires')

So if that works for order_by, shouldn't we also be able to specify multiple fields for the “latest” criteria?

Django 2.0 now allows multiple fields in this way when specifying the QuerySet.latest (and QuerySet.earliest) call, and also for the get_latest_by model option:

from django.db import models

class Subscription(models.Model):
    """ A subscription to our magazine. """

    created = models.DateField(auto_now_add=True)
    renewed = models.DateField(null=True)
    next_reminder = models.DateField()
    expires = models.DateField()
    email_address = models.EmailField()

    class Meta:
        get_latest_by = ['renewed', '-next_reminder', 'expires']
>>> latest_subscription = Subscription.objects.latest(
...     'renewed', '-next_reminder', 'expires')
>>> latest_subscription.email_address
'michele58@barton-bird.biz'

Do you have questions about Django, or want to hire me for some work in a Django-related project? Come chat to me either privately at my Matrix address @bignose:matrix.org, or in the public Django chat channel.