JSONField dengan SQL Server

Artikel ini menjelaskan cara kerja Django JSONField dengan SQL Server melalui mssql-django backend, termasuk pencarian dan batasan yang didukung.

Prasyarat

  • SQL Server 2017 atau versi yang lebih baru, Azure SQL Database, atau database SQL di Fabric
  • mssql-django 1.2 atau yang lebih baru

Membuat database SQL

Buat atau sambungkan ke database SQL di salah satu platform berikut:

Bagaimana JSONField memetakan ke SQL Server

JSONField milik Django dipetakan ke nvarchar(max) dengan kendala pemeriksaan JSON di SQL Server. Backend menggunakan fungsi JSON bawaan SQL Server (JSON_VALUE, , JSON_QUERY) ISJSONuntuk mengimplementasikan pencarian dan kueri.

Menentukan model dengan JSONField

Tambahkan model berikut ke myapp/models.py. Contoh dalam artikel ini menggunakan Item model sehingga tidak berkonflik dengan Product model dari mulai cepat 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)

Buat dan terapkan migrasi sehingga tabel yang mendasar ada di SQL Server:

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

Menyimpan dan mengambil data JSON

Buka shell Django dengan python manage.py shell. Pada prompt >>>, impor model:

from myapp.models import Item

Buat rekaman dengan data JSON:

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

Ambil catatan dan akses nilai JSON:

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

Pencarian yang didukung

Backend mssql-django mendukung pencarian JSONField berikut:

Pencarian kunci/indeks

Akses nilai JSON berlapis menggunakan sintaks garis bawah ganda Django:

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

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

mengandung

Note

Pencarian contains tidak didukung di backend mssql-django. Gunakan has_key dengan pencarian jalur kunci sebagai alternatif:

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

has_key

Periksa apakah kunci tertentu ada:

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

has_keys

Periksa apakah semua kunci yang ditentukan ada:

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

has_any_keys

Periksa apakah salah satu kunci yang ditentukan ada:

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

isnull

Pencarian isnull memiliki perilaku khusus dengan 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

Di backend mssql-django, jika sebuah kunci ada tetapi bernilai JSON null, has_key mengembalikan QuerySet kosong. Ini berbeda dari PostgreSQL, di mana has_key mengembalikan True terlepas dari nilainya. Pencarian isnull=True mengembalikan objek di mana kunci tidak ada dan objek di mana nilainya adalah null.

persis dengan None

Pencarian exact tidak mendukung nilai None. Kueri berikut mengembalikan QuerySet kosong:

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

Gunakan isnull lookup sebagai gantinya untuk menemukan nilai null.

Limitations

  • Pembaruan massal dengan JSONField: Ada beberapa kasus khusus saat menggunakan bulk_update dengan nilai JSONField, terutama pada Django 5.2 dan versi yang lebih baru. Untuk informasi selengkapnya, lihat Batasan dan fitur yang tidak didukung di mssql-django.
  • EKSPRESI CASE WHEN: Pada Django 5.2 dan versi yang lebih baru, operasi JSONField tertentu di dalam ekspresi CASE WHEN mungkin menghasilkan hasil yang tidak terduga.
  • sama persis dengan None: Gunakan isnull alih-alih exact untuk memfilter nilai null JSON.
  • has_key dengan nilai null: has_key mengembalikan QuerySet kosong untuk kunci yang ada, tetapi nilainya adalah null.
  • Karakter kutipan literal dalam nilai string JSON: Pencarian kesetaraan pada nilai string JSON yang berisi karakter literal " (misalnya, metadata={"description": '"quoted"'}) mungkin tidak cocok dengan baris yang disimpan. Nilai yang berisi tanda kutip tersimpan dengan benar, tetapi tidak selalu dapat diambil kembali melalui pencarian pada field.