18

I'm using Django 1.9 and Postgres 9.5. I have a model (MyModel) with a JSONField (django.contrib.postgres.fields). The JSON value has the same structure in all the objects in the model.

{
"key1": int_val_1,
"key2": int_val_2
}

I want to order my queryset by a value of a specified key in my JSONField. Something like

MyModel.objects.annotate(val=F('jsonfield__key1')).order_by('val')

This does not work - i get the following error

Cannot resolve keyword 'key1' into field. Join on 'jsonfield' not permitted.

Is there anyway i can achieve this?

1

3 Answers 3

28

for Django >= 1.11, you can use:

from django.contrib.postgres.fields.jsonb import KeyTextTransform
MyModel.objects.annotate(val=KeyTextTransform('key1', 'jsonfield')).order_by('val')
Sign up to request clarification or add additional context in comments.

4 Comments

How would I use that for nested json fields? For example jsonfield['key1']['key2']
nested fields with KeyTextTransform is a bit PITA currently - e.g. MyModel.objects.annotate(val=KeyTextTransform('key1', 'jsonfield')).annotate(val1=KeyTextTransform('key2', 'val')).
so if you have loads of nested JSON fields then the Django query will be nested as hell too: .annotate( n=Cast( KeyTextTransform( 'value', KeyTextTransform( 'field2', KeyTextTransform( 'field1', 'data'), ), ), output_field=FloatField()). The logic for KeyTextTransform is to traverse the fields in reverse order.
This answer shows an excellent approach for nested fields: stackoverflow.com/a/55076146/5153500
4

An updated answer for this question:

At current time of writing (Django 3.1), you can now order exactly as you had hoped without needing any helper functions:

MyModel.objects.order_by('jsonfield__key1')

1 Comment

But (v2.2) there seems to be a bug so this does not work in annotations.
0

JSONExtract is use with mysql Syntax ('json-field-name', 'json-field-key') ~Q is used for "not equal"

from django_mysql.models.functions import JSONExtract Listing.objects.annotate(weight=JSONExtract('package_dimensions','$.p>ackage_weight')).filter(~Q(weight=0))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.