【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>]>
相关推荐
实战派K8S&DB8 分钟前
如何在内网配置 TiDB 数据库 Agent
数据库·人工智能·分布式·tidb
实战派K8S&DB14 分钟前
《基于 Dify + FastAPI + PyTiDB 搭建大模型驱动的 TiDB 智能运维 Agent》
运维·数据库·分布式·云原生·tidb·fastapi
SelectDB20 分钟前
Apache Doris 5.0 年度版本前瞻(一):构建统一的多模湖仓实时分析平台
大数据·数据库·数据分析
小白学大数据42 分钟前
超简单:用 Python 让 Excel 飞起来:用 openpyxl 把重复报表整理交给脚本
开发语言·数据库·python·excel
西索斯coding1 小时前
doubao-seed-2.1-turbo 调用一直 401 怎么办?pro 版同样的 Key 却正常——5 分钟排查定位指南
java·服务器·数据库·ai
袋鼠云数栈1 小时前
整库迁移与分库分表同步:批量数据搬迁的配置简化思路
jvm·数据库·oracle
小蒜学长2 小时前
基于Springboot+Vue的环保行动志愿者招募系统设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
cfm_29142 小时前
Spring事务
数据库·spring·oracle
一只鹿鹿鹿2 小时前
SCM流程图参考(PPT文件)
大数据·数据库·web安全·系统安全·流程图
ClouGence3 小时前
CloudDM 支持达梦、KingbaseES、GoldenDB,国产数据库也能统一管起来
数据库·sql·开源