0x0c -- Django -- 模型介绍 -- 12 -- QuerySet -- 执行查询 -- 查询 JSONField

本文详细介绍了Django中JSONField的使用,包括如何保存和查询None值,键、索引和路径转换的方法,以及contains、contained_by、has_key、has_keys和has_any_keys等查询操作。特别指出,None值在JSONField中的处理方式,以及不同数据库平台的注意事项。内容涵盖了JSON数据的存储、查询和过滤技巧。
摘要由CSDN通过智能技术生成


JSONField 里的查找实现是不一样的,主要因为存在key转换。

# 示例
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

0x01 – 保存和查询 None 值

与其他字段一样,当 None 作为字段值来保存时,将像 SQL 的 NULL 值一样保存。
虽然不建议这样做,但可以使用 Value('null') 来存储 JSON 的 null 值。

无论存储哪个值,当从数据库中检索时,Python表示JSON的空值和 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 。


0x02 – Key, index, 和路径转换

为了查询给定的字典键,请将该键作为查询名:

>>> 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,索引和路径转换也可以用:icontains, endswith, iendswith, iexact, regex, iregex, startswith, istartswith, lt, lte, gt, gte, 以及:ref:containment-and-key-lookups 。

注解
由于键路径查询的工作方式,exclude() 和 filter() 不能保证产生详尽的集合。如果你想包含没有路径的对象,请添加 isnull 查找。

警告
因为任何字符串在JSON对象中都可以作为key,因此除了下面列出的这些查找会被解释为键查找。不会引发任何错误。要特别小心输入错误,并且要检查查询是否正常工作。

MariaDB 和 Oracle 用户
对Key, 索引, 或者路径转换使用 order_by() 会使用值的字符串表示来进行对象排序。这是因为MariaDB 和 Oracle 数据库不支持将JSON值转换成它们的等效SQL值的函数。

Oracle 用户
在Oracle数据库上,在 exclude() 查询里使用 None 作为查找值将返回给定路径上没有 null 值的对象。在其他数据库后端,查询将返回具有路径和不为 null 值的对象。

PostgreSQL 用户
在 PostgreSQL 上,如果只使用一个key或索引,那么会使用 SQL 运算符 -> 。如果使用多个操作符,那么会使用 #> 运算符。


0x03 – 包含与键查找

0x03 – 1 – 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>]>

Oracle 和 SQLite 不支持 contained 。


0x03 – 2 – 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>]>

Oracle 和 SQLite 不支持 contained_by 。


0x03 – 3 – 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>]>

0x03 – 4 – 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>]>

0x03 – 5 – 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>]>

2021年10月8日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值