Search code examples
pythondjangodjango-models

Custom ordering in Django


How do you define a specific ordering in Django QuerySets?

Specifically, if I have a QuerySet like so: ['a10', 'a1', 'a2'].

Regular order (using Whatever.objects.order_by('someField')) will give me ['a1', 'a10', 'a2'], while I am looking for: ['a1', 'a2', 'a10'].

What is the proper way to define my own ordering technique?


Solution

  • As far as I'm aware, there's no way to specify database-side ordering in this way as it would be too backend-specific. You may wish to resort to good old-fashioned Python sorting:

    class Foo(models.Model):
        name = models.CharField(max_length=128)
    
    Foo.objects.create(name='a10')
    Foo.objects.create(name='a1')
    Foo.objects.create(name='a2')
    
    ordered = sorted(Foo.objects.all(), key=lambda n: (n[0], int(n[1:])))
    print ordered # yields a1, a2, 10
    

    If you find yourself needing this kind of sorting a lot, I'd recommend making a custom models.Manager subclass for your model that performs the ordering. Something like:

    class FooManager(models.Manager):
        def in_a_number_order(self, *args, **kwargs):
            qs = self.get_query_set().filter(*args, **kwargs)
            return sorted(qs, key=lambda n: (n[0], int(n[1:])))
    
    class Foo(models.Model):
        ... as before ...
        objects = FooManager()
    
    print Foo.objects.in_a_number_order()
    print Foo.objects.in_a_number_order(id__in=[5, 4, 3]) # or any filtering expression