【Django】执行查询——查询JSONField

JSONField

本篇的例子以下面这个模型为基础:

python 复制代码
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值

在使用JSONField时,要注意空值的处理,注意区分SQL NULLJSON null

保存None值

我们首先创建两个Dog实例

python 复制代码
from django.db.models import Value, JSONField

>>> Dog.objects.create(name="Max", data=None)  # SQL NULL.
<Dog: Max>
>>> Dog.objects.create(name="Archie", data=Value(None, JSONField()))  # JSON null.
<Dog: Archie>

观察两个实例在数据库中的表现,可以发现SQL NULLJSON null是不一样的。

查询None值

查询时,None值将被解释为JSON null,要查询SQL NULL,需要使用isnull

python 复制代码
>>> Dog.objects.filter(data=None)
<QuerySet [<Dog: Archie>]>
>>> Dog.objects.filter(data=Value(None, JSONField()))
<QuerySet [<Dog: Archie>]>
>>> Dog.objects.filter(data__isnull=True)
<QuerySet [<Dog: Max>]>
>>> Dog.objects.filter(data__isnull=False)
<QuerySet [<Dog: Archie>]>

对比可以发现,data=None在保存时存储为SQL NULL,查询时解释为JSON null

根据键值查找

根据json数据的键进行查找,用__连接,可以多个键连接一起,如果某个值是一个列表,要进行索引,就用整数代表该列表的索引。

例子:

python 复制代码
>>> 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>]>
# 查询缺少的键,使用isnull查找
>>> Dog.objects.create(name="Shep", data={"breed": "collie"})
<Dog: Shep>
>>> Dog.objects.filter(data__owner__isnull=True)
<QuerySet [<Dog: Shep>]>

包含与键查找

contains

contains 查询返回的对象是那些包含给定键值对的顶层字段的对象。

python 复制代码
>>> 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 查询的反向。 要查询的对象满足这样的条件:其该字段对应的数据是传递的值的子集。

python 复制代码
>>> 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

返回数据顶层的键中有给定值的对象。

python 复制代码
>>> 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

返回数据顶层的键都包含在给定列表中的对象。

python 复制代码
>>> 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

返回数据顶层的键中有至少1个在给定列表中的对象,比has_keys条件更宽松。

python 复制代码
>>> 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>]>
相关推荐
不辉放弃41 分钟前
ZooKeeper 是什么?
数据库·大数据开发
Goona_1 小时前
拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统
数据库·python·sql·excel·pyqt
程序员编程指南2 小时前
Qt 数据库连接池实现与管理
c语言·数据库·c++·qt·oracle
幼儿园老大*4 小时前
数据中心-时序数据库InfluxDB
数据库·时序数据库
daixin88484 小时前
Redis过期数据的删除策略是什么?有哪些?
数据库·redis·缓存
陪我一起学编程4 小时前
MySQL创建普通用户并为其分配相关权限的操作步骤
开发语言·数据库·后端·mysql·oracle
小王子10244 小时前
Django实时通信实战:WebSocket与ASGI全解析(下)
python·websocket·django
Albert Tan5 小时前
ORACLE DATABASE 23AI+Apex+ORDS -纯享版
数据库·oracle
程序员编程指南5 小时前
Qt OpenGL 集成:开发 3D 图形应用
c语言·数据库·c++·qt·3d