JSONField com SQL Server

Este artigo explica como o JSONField Django funciona com o SQL Server por meio do back-end mssql-django, incluindo as consultas compatíveis e as limitações.

Pré-requisitos

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

Como o JSONField é mapeado para SQL Server

O Django mapeia JSONField para nvarchar(max) com uma restrição de verificação JSON em SQL Server. O back-end usa as funções JSON internas do SQL Server (JSON_VALUE, JSON_QUERY, ) ISJSONpara implementar pesquisas e consultas.

Definir um modelo com JSONField

Adicione o modelo a seguir a myapp/models.py. Os exemplos neste artigo usam um Item modelo para que eles não entrem em conflito com o Product modelo do 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)

Gere e aplique a migração para que a tabela subjacente exista em SQL Server:

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

Armazenar e recuperar dados JSON

Abra o shell do Django com python manage.py shell. No prompt >>>, importe o modelo:

from myapp.models import Item

Crie um registro com dados JSON:

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

Recupere o registro e acesse os valores JSON:

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

Pesquisas com suporte

O mssql-django backend oferece suporte às seguintes consultas de JSONField:

Pesquisas de chave/índice

Acesse valores JSON aninhados usando a sintaxe de sublinhado duplo 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()

contém

Note

A consulta contains não é compatível com o backend mssql-django. Use has_key com consultas por caminho de chave como alternativa:

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

has_key

Verifique 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 existe alguma das chaves especificadas:

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

isnull

A consulta isnull apresenta 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

mssql-django No back-end, se uma chave existir, mas tiver um valor JSONnull, has_key retornará um QuerySet vazio. Isso difere do PostgreSQL, em que has_key retorna True independentemente do valor. A isnull=True pesquisa retorna objetos em que a chave não existe e objetos onde o valor está null.

exatamente com None

A pesquisa exact não oferece suporte a valores None. A consulta a seguir retorna um QuerySet vazio:

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

Em vez disso, use a isnull pesquisa para localizar valores nulos.

Limitations

  • Atualizações em massa com JSONField: existem alguns casos extremos ao usar bulk_update com valores de JSONField, principalmente no Django 5.2 e em versões posteriores. Para obter mais informações, consulte Limitações e recursos sem suporte no mssql-django.
  • Expressões CASE WHEN: No Django 5.2 e versões posteriores, determinadas operações JSONField dentro de expressões CASE WHEN podem produzir resultados inesperados.
  • exact com None: Use isnull em vez de exact para filtrar valores nulos em JSON.
  • has_key com valores nulos: has_key retorna um QuerySet vazio para chaves que existem, mas têm um null valor.
  • Caracteres de aspas literais em valores de string em JSON: consultas de igualdade em valores de string em JSON que contêm caracteres literais " (por exemplo, metadata={"description": '"quoted"'}) podem não corresponder à linha armazenada. Os valores que contêm caracteres de aspas são armazenados corretamente, mas não são recuperáveis de forma confiável por meio de pesquisas de campo.