带有SQL Server的 JSONField

本文介绍 Django 的 JSONField 如何通过 mssql-django 后端与 SQL Server 配合使用,包括支持的查找和限制。

先决条件

  • SQL Server 2016 或更高版本(需要 JSON 函数)
  • mssql-django 1.2 或更高版本

JSONField 如何映射到SQL Server

Django 的 JSONField 在 SQL Server 中映射为 nvarchar(max),并带有 JSON 检查约束。 后端使用SQL Server的内置 JSON 函数(JSON_VALUE、、JSON_QUERYISJSON)来实现查找和查询。

使用 JSONField 定义模型

将以下模型添加到 myapp/models.py. 本文中的示例使用模型 Item ,因此它们不会与 ProductDjango 快速入门中的模型冲突。

from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=100)
    metadata = models.JSONField(default=dict)
    tags = models.JSONField(null=True, blank=True)

生成并应用迁移,以便基础表存在于SQL Server中:

python manage.py makemigrations myapp
python manage.py migrate myapp

存储和检索 JSON 数据

使用 python manage.py shell.. 打开 Django shell。 在 >>> 提示符处,导入模型:

from myapp.models import Item

使用 JSON 数据创建记录:

item = Item.objects.create(
    name="Widget",
    metadata={"color": "blue", "weight": 1.5, "dimensions": {"height": 10, "width": 5}},
    tags=["sale", "new"],
)

检索记录并访问 JSON 值:

item = Item.objects.get(name="Widget")
print(item.metadata["color"])  # "blue"
print(item.tags)  # ["sale", "new"]

受支持的查找

mssql-django 后端支持以下 JSONField 查找:

键查找/索引查找

使用 Django 的双下划线语法访问嵌套 JSON 值:

# Filter by nested key value
Item.objects.filter(metadata__color="blue").values()

# Access nested objects
Item.objects.filter(metadata__dimensions__height=10).values()

包含

注释

mssql-django 后端不支持 contains 查找操作。 可改用 has_key 配合键路径查找:

# Instead of: Item.objects.filter(metadata__contains={"color": "blue"})
# Use key-path lookup:
Item.objects.filter(metadata__color="blue").values()

has_key

检查是否存在特定密钥:

Item.objects.filter(metadata__has_key="color").values()

has_keys

检查是否存在所有指定的密钥:

Item.objects.filter(metadata__has_keys=["color", "weight"]).values()

has_any_keys

检查是否存在任何指定的键:

Item.objects.filter(metadata__has_any_keys=["color", "size"]).values()

isnull

isnull 查找在 SQL Server 中具有特定行为:

# Returns objects where the key doesn't exist AND keys with None value
Item.objects.filter(metadata__color__isnull=True).values()

# Returns objects where the key exists and has a non-null value
Item.objects.filter(metadata__color__isnull=False).values()

注释

mssql-django 后端,如果某个密钥存在但具有 JSON null 值, has_key 则返回一个空的 QuerySet。 这与 PostgreSQL 不同,无论值如何,都会 has_key 返回 Trueisnull=True 查找会返回键不存在的对象以及值为 null 的对象。

精确且无

exact 查找不支持 None 值。 以下查询返回空的 QuerySet:

# Returns empty QuerySet - use isnull lookup instead
Item.objects.filter(metadata__color=None).values()

请改用 isnull 查找来查找 null 值。

Limitations

  • 使用 JSONField 进行批量更新:在将 bulk_update 用于 JSONField 值时,存在一些特殊情况,尤其是在 Django 5.2 及更高版本中。 有关详细信息,请参阅 mssql-django 中的限制和不支持的功能
  • CASE WHEN 表达式:在 Django 5.2 及更高版本中,CASE WHEN 表达式中的某些 JSONField 操作可能会产生意外的结果。
  • exact with None:使用 isnull 而不是 exact 来筛选 JSON null 值。
  • has_key 带有 null 值时:对于存在但值为 null 的键,has_key 会返回空 QuerySet。
  • JSON 字符串值中的文字引号字符:对包含文本 " 字符(例如, metadata={"description": '"quoted"'})的 JSON 字符串值的相等性查找可能与存储的行不匹配。 包含引号字符的值能够正确存储,但却无法通过字段查找可靠地检索出来。