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 2016 atau yang lebih baru (fungsi JSON diperlukan)
  • mssql-django 1.2 atau yang lebih baru

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.