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

geteshi
2024-07-02 / 0 评论 / 18 阅读 / 正在检测是否收录...

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值

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

保存None值

我们首先创建两个Dog实例

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

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数据的键进行查找,用__连接,可以多个键连接一起,如果某个值是一个列表,要进行索引,就用整数代表该列表的索引。
例子:

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 查询返回的对象是那些包含给定键值对的顶层字段的对象。

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

返回数据顶层的键中有至少1个在给定列表中的对象,比has_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>]>
0

评论 (0)

取消