JSONField для SQL Server

В этой статье объясняется, как JSONField Django работает с SQL Server через модуль mssql-django, включая поддерживаемые операции поиска и ограничения.

Необходимые условия

  • SQL Server 2016 или более поздней версии (необходимы функции JSON)
  • mssql-django 1.2 или более поздней версии

Сопоставление JSONField с SQL Server

В Django JSONField соответствует nvarchar(max) с ограничением проверки JSON в SQL Server. Серверная часть использует встроенные JSON-функции SQL Server (JSON_VALUE, JSON_QUERY, ISJSON) для реализации поиска и запросов.

Определение модели с помощью JSONField

Добавьте следующую модель в myapp/models.py. В примерах в этой статье используется Item модель, поэтому они не конфликтуют с моделью Product из краткого руководства по Django.

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

Откройте оболочку Django с помощью команды python manage.py 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:

Поиск ключей и индексов

Доступ к вложенным значениям JSON с помощью синтаксиса двойного подчеркивания Django:

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

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

содержит

Note

Поиск contains не поддерживается в серверной части mssql-django. Используйте 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()

Note

На стороне mssql-django, если ключ существует, но имеет значение JSON null, has_key возвращает пустой QuerySet. Это отличается от PostgreSQL, где has_key возвращается True независимо от значения. Оператор поиска isnull=True возвращает объекты, в которых ключ отсутствует, и объекты, в которых значение равно null.

точное соответствие с None

Поиск exact не поддерживает значения None. Следующий запрос возвращает пустой набор запросов:

# 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 и более поздних версиях некоторые операции JSONField внутри выражений CASE WHEN могут привести к непредвиденным результатам.
  • exact с None: используйте isnull вместо exact, чтобы фильтровать значения JSON со значением null.
  • has_key со значениями NULL: has_key возвращает пустой QuerySet для ключей, которые существуют, но имеют значение null.
  • Символы литеральных кавычек в строковых значениях JSON: подстановки равенства в строковых значениях JSON, содержащих литеральные " символы (например, metadata={"description": '"quoted"'}), могут не соответствовать сохраненной строке. Значения, содержащие символы кавычек, сохраняются правильно, но их не всегда удаётся надёжно получить при поиске по полям.