Django 1.9 JSONField order_by

Since Django 1.11, django.contrib.postgres.fields.jsonb.KeyTextTransform can be used instead of RawSQL

from django.contrib.postgres.fields.jsonb import KeyTextTransform

qs = RatebookEntry.objects.all()
qs = qs.annotate(manufacturer_name=KeyTextTransform('manufacturer_name', 'data'))
qs = qs.order_by('manufacturer_name')
# or...
qs = qs.order_by('-manufacturer_name')

On Django 1.10, you'll have to subclass KeyTransform yourself:

from django.contrib.postgres.fields.jsonb import KeyTransform

class KeyTextTransform(KeyTransform):
    operator = '->>'
    nested_operator = '#>>'
    _output_field = TextField()

Note: the difference between KeyTransform and KeyTextTransform is that KeyTransform will return the JSON representation of the object, whereas KeyTextTransform will return the value of the object.

For example, if data is {"test": "stuff"}, KeyTextTransform will return 'stuff', whereas KeyTransform will return '"stuff"' (which can be parsed by json.loads)


Following Daniil Ryzhkov answer and Eugene Prikazchikov comment, you should be able to sort ASC and DESC on JSON data fields without annotating your queryset, by using both RawSQL and OrderBy. Also, you can perform case insensitive sorting by adding LOWER:

from django.db.models.expressions import RawSQL, OrderBy

RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("LOWER(data->>%s)", ("manufacturer_name",)), descending=True))

To compare integers fields, you can cast as integer:

RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("cast(data->>%s as integer)", ("annual_mileage",)), descending=True))

As Julien mentioned ordering on JSONField is not yet supported in Django. But it's possible via RawSQL using PostgreSQL functions for jsonb. In OP's case:

from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))