mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Thanks to Adam Johnson, Carlton Gibson, Mariusz Felisiak, and Raphael Michel for mentoring this Google Summer of Code 2019 project and everyone else who helped with the patch. Special thanks to Mads Jensen, Nick Pope, and Simon Charette for extensive reviews. Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
@@ -798,6 +798,236 @@ being evaluated and therefore populate the cache::
|
||||
Simply printing the queryset will not populate the cache. This is because
|
||||
the call to ``__repr__()`` only returns a slice of the entire queryset.
|
||||
|
||||
.. _querying-jsonfield:
|
||||
|
||||
Querying ``JSONField``
|
||||
======================
|
||||
|
||||
Lookups implementation is different in :class:`~django.db.models.JSONField`,
|
||||
mainly due to the existence of key transformations. To demonstrate, we will use
|
||||
the following example model::
|
||||
|
||||
from django.db import models
|
||||
|
||||
class Dog(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
data = models.JSONField(null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
Storing and querying for ``None``
|
||||
---------------------------------
|
||||
|
||||
As with other fields, storing ``None`` as the field's value will store it as
|
||||
SQL ``NULL``. While not recommended, it is possible to store JSON scalar
|
||||
``null`` instead of SQL ``NULL`` by using :class:`Value('null')
|
||||
<django.db.models.Value>`.
|
||||
|
||||
Whichever of the values is stored, when retrieved from the database, the Python
|
||||
representation of the JSON scalar ``null`` is the same as SQL ``NULL``, i.e.
|
||||
``None``. Therefore, it can be hard to distinguish between them.
|
||||
|
||||
This only applies to ``None`` as the top-level value of the field. If ``None``
|
||||
is inside a :py:class:`list` or :py:class:`dict`, it will always be interpreted
|
||||
as JSON ``null``.
|
||||
|
||||
When querying, ``None`` value will always be interpreted as JSON ``null``. To
|
||||
query for SQL ``NULL``, use :lookup:`isnull`::
|
||||
|
||||
>>> Dog.objects.create(name='Max', data=None) # SQL NULL.
|
||||
<Dog: Max>
|
||||
>>> Dog.objects.create(name='Archie', data=Value('null')) # JSON null.
|
||||
<Dog: Archie>
|
||||
>>> Dog.objects.filter(data=None)
|
||||
<QuerySet [<Dog: Archie>]>
|
||||
>>> Dog.objects.filter(data=Value('null'))
|
||||
<QuerySet [<Dog: Archie>]>
|
||||
>>> Dog.objects.filter(data__isnull=True)
|
||||
<QuerySet [<Dog: Max>]>
|
||||
>>> Dog.objects.filter(data__isnull=False)
|
||||
<QuerySet [<Dog: Archie>]>
|
||||
|
||||
Unless you are sure you wish to work with SQL ``NULL`` values, consider setting
|
||||
``null=False`` and providing a suitable default for empty values, such as
|
||||
``default=dict``.
|
||||
|
||||
.. note::
|
||||
|
||||
Storing JSON scalar ``null`` does not violate :attr:`null=False
|
||||
<django.db.models.Field.null>`.
|
||||
|
||||
.. fieldlookup:: jsonfield.key
|
||||
|
||||
Key, index, and path transforms
|
||||
-------------------------------
|
||||
|
||||
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: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
|
||||
<Dog: Meg>
|
||||
>>> 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 transform 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 :lookup:`contains <jsonfield.contains>` lookup instead.
|
||||
|
||||
To query for missing keys, use the ``isnull`` lookup::
|
||||
|
||||
>>> Dog.objects.create(name='Shep', data={'breed': 'collie'})
|
||||
<Dog: Shep>
|
||||
>>> Dog.objects.filter(data__owner__isnull=True)
|
||||
<QuerySet [<Dog: Shep>]>
|
||||
|
||||
.. note::
|
||||
|
||||
The lookup examples given above implicitly use the :lookup:`exact` lookup.
|
||||
Key, index, and path transforms can also be chained with:
|
||||
:lookup:`contains`, :lookup:`icontains`, :lookup:`endswith`,
|
||||
:lookup:`iendswith`, :lookup:`iexact`, :lookup:`regex`, :lookup:`iregex`,
|
||||
:lookup:`startswith`, :lookup:`istartswith`, :lookup:`lt`, :lookup:`lte`,
|
||||
:lookup:`gt`, and :lookup:`gte` lookups.
|
||||
|
||||
.. 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.
|
||||
|
||||
.. admonition:: MariaDB and Oracle users
|
||||
|
||||
Using :meth:`~django.db.models.query.QuerySet.order_by` on key, index, or
|
||||
path transforms will sort the objects using the string representation of
|
||||
the values. This is because MariaDB and Oracle Database do not provide a
|
||||
function that converts JSON values into their equivalent SQL values.
|
||||
|
||||
.. admonition:: Oracle users
|
||||
|
||||
On Oracle Database, using ``None`` as the lookup value in an
|
||||
:meth:`~django.db.models.query.QuerySet.exclude` query will return objects
|
||||
that do not have ``null`` as the value at the given path, including objects
|
||||
that do not have the path. On other database backends, the query will
|
||||
return objects that have the path and the value is not ``null``.
|
||||
|
||||
.. admonition:: PostgreSQL users
|
||||
|
||||
On PostgreSQL, if only one key or index is used, the SQL operator ``->`` is
|
||||
used. If multiple operators are used then the ``#>`` operator is used.
|
||||
|
||||
Containment and key operations
|
||||
------------------------------
|
||||
|
||||
.. fieldlookup:: jsonfield.contains
|
||||
|
||||
``contains``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The :lookup:`contains` lookup is overridden on ``JSONField``. The returned
|
||||
objects are those where the given ``dict`` of key-value pairs are all
|
||||
contained in the top-level of the field. For example::
|
||||
|
||||
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
|
||||
<Dog: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
|
||||
<Dog: Meg>
|
||||
>>> Dog.objects.create(name='Fred', data={})
|
||||
<Dog: Fred>
|
||||
>>> Dog.objects.filter(data__contains={'owner': 'Bob'})
|
||||
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
|
||||
>>> Dog.objects.filter(data__contains={'breed': 'collie'})
|
||||
<QuerySet [<Dog: Meg>]>
|
||||
|
||||
.. fieldlookup:: jsonfield.contained_by
|
||||
|
||||
``contained_by``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
This is the inverse of the :lookup:`contains <jsonfield.contains>` lookup - the
|
||||
objects returned will be those where the key-value pairs on the object are a
|
||||
subset of those in the value passed. For example::
|
||||
|
||||
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
|
||||
<Dog: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
|
||||
<Dog: Meg>
|
||||
>>> Dog.objects.create(name='Fred', data={})
|
||||
<Dog: Fred>
|
||||
>>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
|
||||
<QuerySet [<Dog: Meg>, <Dog: Fred>]>
|
||||
>>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
|
||||
<QuerySet [<Dog: Fred>]>
|
||||
|
||||
.. admonition:: Oracle
|
||||
|
||||
``contained_by`` is not supported on Oracle.
|
||||
|
||||
.. fieldlookup:: jsonfield.has_key
|
||||
|
||||
``has_key``
|
||||
~~~~~~~~~~~
|
||||
|
||||
Returns objects where the given key is in the top-level of the data. For
|
||||
example::
|
||||
|
||||
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
|
||||
<Dog: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
|
||||
<Dog: Meg>
|
||||
>>> Dog.objects.filter(data__has_key='owner')
|
||||
<QuerySet [<Dog: Meg>]>
|
||||
|
||||
.. fieldlookup:: jsonfield.has_any_keys
|
||||
|
||||
``has_keys``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Returns objects where all of the given keys are in the top-level of the data.
|
||||
For example::
|
||||
|
||||
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
|
||||
<Dog: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
|
||||
<Dog: Meg>
|
||||
>>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
|
||||
<QuerySet [<Dog: Meg>]>
|
||||
|
||||
.. fieldlookup:: jsonfield.has_keys
|
||||
|
||||
``has_any_keys``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Returns objects where any of the given keys are in the top-level of the data.
|
||||
For example::
|
||||
|
||||
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
|
||||
<Dog: Rufus>
|
||||
>>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
|
||||
<Dog: Meg>
|
||||
>>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
|
||||
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
|
||||
|
||||
.. _complex-lookups-with-q:
|
||||
|
||||
Complex lookups with ``Q`` objects
|
||||
|
||||
Reference in New Issue
Block a user