JSONField com SQL Server

Este artigo explica como o Django JSONField funciona com o SQL Server através do mssql-django backend, incluindo consultas suportadas e limitações.

Pré-requisitos

  • SQL Server 2016 ou posterior (funções JSON são obrigatórias)
  • mssql-django 1.2 ou posterior

Como o JSONField faz o mapeamento para o SQL Server

O Django JSONField mapeia para nvarchar(max) com uma restrição de verificação JSON no SQL Server. O backend utiliza as funções JSON integradas do SQL Server (JSON_VALUE, JSON_QUERY, ISJSON) para implementar pesquisas e consultas.

Defina um modelo com JSONField

Adicione o seguinte modelo a myapp/models.py. Os exemplos deste artigo usam um modelo Item para não entrarem em conflito com o modelo Product do guia de início rápido do 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)

Gerar e aplicar a migração para que a tabela subjacente exista no SQL Server:

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

Armazenar e recuperar dados JSON

Abra a carcaça de Django com python manage.py shell. Na linha de comandos >>>, importe o modelo:

from myapp.models import Item

Crie um registo com dados JSON:

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

Recuperar o registo e aceder aos valores JSON:

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

Consultas suportadas

O mssql-django backend suporta as seguintes pesquisas JSONField:

Consultas de chaves/índices

Aceda a valores JSON aninhados usando a sintaxe de duplo sublinhado do Django:

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

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

contains

Note

A contains pesquisa não é suportada no mssql-django backend. Utilize has_key como alternativa para pesquisas por caminho de chave:

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

has_key

Verifica se existe uma chave específica:

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

has_keys

Verifique se todas as chaves especificadas existem:

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

has_any_keys

Verifique se alguma das chaves especificadas existe:

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

é nulo

A isnull pesquisa tem um comportamento específico com o 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

No backend mssql-django, se existir uma chave mas esta tiver um valor JSON null, has_key devolve um QuerySet vazio. Isto difere do PostgreSQL, onde has_key retorna True independentemente do valor. A isnull=True pesquisa devolve objetos onde a chave não existe e objetos cujo valor é null.

exato com Nenhum

A pesquisa exact não suporta valores None. A consulta seguinte devolve um QuerySet vazio:

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

Utilize a pesquisa isnull em vez disso para encontrar valores nulos.

Limitations

  • Atualizações em massa com JSONField: Existem alguns casos limites quando se usa bulk_update com valores JSONField, particularmente no Django 5.2 e versões posteriores. Para mais informações, consulte Limitações e funcionalidades não suportadas no mssql-django.
  • Expressões CASE WHEN: Em versões Django 5.2 e posteriores, certas operações JSONField dentro de expressões CASE WHEN podem produzir resultados inesperados.
  • exato com None: Use isnull em vez de exact para filtrar por valores JSON nulos.
  • has_key com valores nulos: has_key devolve um QuerySet vazio para chaves que existem mas têm um null valor.
  • Caracteres de aspas literais em valores de strings JSON: Pesquisas por igualdade em valores de strings JSON que contenham aspas literais " (por exemplo, metadata={"description": '"quoted"'}) podem não corresponder à linha guardada. Os valores que contêm caracteres de aspas armazenam-se corretamente, mas não são recuperáveis de forma fiável através de consultas de campo.