JSONField ¶
See also
JSONField
¶
- class JSONField ( encoder = None , ** options ) ¶
-
A field for storing JSON encoded data. In Python the data is represented in its Python native format: dictionaries, lists, strings, numbers, booleans and
None
.- encoder ¶
-
An optional JSON-encoding class to serialize data types not supported by the standard JSON serializer (
datetime
,uuid
, etc.). For example, you can use theDjangoJSONEncoder
class or any otherjson.JSONEncoder
subclass.When the value is retrieved from the database, it will be in the format chosen by the custom encoder (most often a string), so you’ll need to take extra steps to convert the value back to the initial data type (
Model.from_db()
andField.from_db_value()
are two possible hooks for that purpose). Your deserialization may need to account for the fact that you can’t be certain of the input type. For example, you run the risk of returning adatetime
that was actually a string that just happened to be in the same format chosen fordatetime
s.
If you give the field a
default
, ensure it’s a callable such asdict
(for an empty default) or a callable that returns a dict (such as a function). Incorrectly usingdefault={}
creates a mutable default that is shared between all instances ofJSONField
.
Note
PostgreSQL has two native JSON based data types:
json
and
jsonb
.
The main difference between them is how they are stored and how they can be
queried. PostgreSQL’s
json
field is stored as the original string
representation of the JSON and must be decoded on the fly when queried
based on keys. The
jsonb
field is stored based on the actual structure
of the JSON which allows indexing. The trade-off is a small additional cost
on writing to the
jsonb
field.
JSONField
uses
jsonb
.
Querying
JSONField
¶
We will use the following example model:
from django.contrib.postgres.fields import JSONField
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=200)
data = JSONField()
def __str__(self):
return self.name
Key, index, and path lookups ¶
To query based on a given dictionary key, use that key as the lookup name:
>>> Dog.objects.create(name='Rufus', data={
... 'breed': 'labrador',
... 'owner': {
... 'name': 'Bob',
... 'other_pets': [{
... 'name': 'Fishy',
... }],
... },
... })
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
Multiple keys can be chained together to form a path lookup:
>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>
If the key is an integer, it will be interpreted as an index lookup in an array:
>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>
If the key you wish to query by clashes with the name of another lookup, use the jsonfield.contains lookup instead.
If only one key or index is used, the SQL operator
->
is used. If multiple
operators are used then the
#>
operator is used.
To query for
null
in JSON data, use
None
as a value:
>>> Dog.objects.filter(data__owner=None)
<QuerySet [<Dog: Meg>]>
To query for missing keys, use the
isnull
lookup:
>>> Dog.objects.create(name='Shep', data={'breed': 'collie'})
>>> Dog.objects.filter(data__owner__isnull=True)
<QuerySet [<Dog: Shep>]>
Warning
Since any string could be a key in a JSON object, any lookup other than those listed below will be interpreted as a key lookup. No errors are raised. Be extra careful for typing mistakes, and always check your queries work as you intend.