Django4.0 执行查询-查询JSONField
JSONField
里的查找实现是不一样的,主要因为存在键转换。为了演示,我们将使用下面这个例子:
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
保存和查询None值
与其他字段一样,将 None
作为字段的值存储为 SQL 的 NULL
。虽然不建议这样做,但可以使用 Value('null')
来存储 JSON 的 null
值。
无论存储哪种值,当从数据库检索时,JSON 标量 null
的 Python 表示法与 SQL 的 NULL
相同,即 None
。因此,可能很难区分它们。
这只适用于 None
值作为字段的顶级值。如果 None
被保存在列表或字典中,它将始终被解释为 JSON 的 null
值。
当查询时,None
值将一直被解释为 JSON 的 null
。要查询 SQL 的 NULL
,请使用 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>]>
除非你确定要使用 SQL 的 NULL
值,否则请考虑设置 null=False
并为空值提供合适的默认值,例如 default=dict
。
注意:保存 JSON 的 null
值不违反 Django 的 null=False
。
键、索引和路径转换
为了查询给定的字典键,请将该键作为查询名:
>>> 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>]>
可以将多个键链接起来形成一个路径查询:
>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>
如果键是个整型,那么它将在数组中被解释成一个索引:
>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>
如果要查询的键与另一个查询的键名冲突,请改用 contains
来查询。
如果查询时缺少键名,请使用 isnull
查询:
>>> Dog.objects.create(name='Shep', data={'breed': 'collie'})
<Dog: Shep>
>>> Dog.objects.filter(data__owner__isnull=True)
<QuerySet [<Dog: Shep>]>
上面给出的例子隐式地使用了 exact
查找。Key
,Index
和Path
转换也可以用:icontains
、endswith
、iendswith
、iexact
、regex
、iregex
、startswith
、istartswith
、lt
、lte
、gt
、gte
以及 包含与键查找 。
由于Key-Path
查询的工作方式,exclude()
和 filter()
不能保证产生详尽的集合。如果你想包含没有路径的对象,请添加 isnull
查找。
包含与键查询
contains
JSONField
上的 contains
查找已被覆盖。返回的对象是那些给定的键值对都包含在顶级字段中的对象。例如:
>>> 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>]>
contained_by
这是 contains
查找逆过程——返回的对象将是那些传递的值中的子集在对象上的键值对。例如:
>>> 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>]>
has_key
返回给定的键位于数据顶层的对象。例如:
>>> 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>]>
has_keys
返回所有给定的键位于数据顶层的对象。例如:
>>> 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>]>
has_any_keys
返回任何给定的键位于数据顶层的对象。例如:
>>> 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>]>
更多建议: