Rumah > pembangunan bahagian belakang > Tutorial Python > Cara Membina Model Data Fleksibel dalam Django dengan JSONField dan Pydantic

Cara Membina Model Data Fleksibel dalam Django dengan JSONField dan Pydantic

Mary-Kate Olsen
Lepaskan: 2024-12-31 18:13:09
asal
405 orang telah melayarinya

How to Build Flexible Data Models in Django with JSONField and Pydantic

Dalam artikel ini, saya akan membimbing anda melalui cara JSONField Django (pembungkus JSON & JSONB) boleh digunakan untuk memodelkan data separa berstruktur dan cara anda boleh menguatkuasakan skema pada itu data menggunakan Pydantic—pendekatan yang sepatutnya dirasakan semula jadi untuk pembangun web Python.

Takrif jenis fleksibel

Mari kita pertimbangkan sistem yang memproses pembayaran, contohnya jadual Transaksi. Ia akan kelihatan seperti ini:

from django.db import models

class Transaction(models.Model):
    # Other relevant fields...
    payment_method = models.JSONField(default=dict, null=True, blank=True)
Salin selepas log masuk
Salin selepas log masuk

tumpuan kami adalah pada medan kaedah_pembayaran. Dalam situasi dunia sebenar, kami akan mempunyai kaedah sedia ada untuk memproses pembayaran:

  • Kad kredit

  • PayPal

  • Beli Sekarang, Bayar Kemudian

  • Cryptocurrency

Sistem kami mesti boleh disesuaikan untuk menyimpan data khusus yang diperlukan oleh setiap kaedah pembayaran sambil mengekalkan struktur yang konsisten dan boleh disahkan.

Kami akan menggunakan Pydantic untuk mentakrifkan skema yang tepat untuk kaedah pembayaran yang berbeza:

from typing import Optional
from pydantic import BaseModel

class CreditCardSchema(BaseModel):
    last_four: str
    expiry_month: int
    expiry_year: int
    cvv: str


class PayPalSchema(BaseModel):
    email: EmailStr
    account_id: str


class CryptoSchema(BaseModel):
    wallet_address: str
    network: Optional[str] = None


class BillingAddressSchema(BaseModel):
    street: str
    city: str
    country: str
    postal_code: str
    state: Optional[str] = None


class PaymentMethodSchema(BaseModel):
    credit_card: Optional[CreditCardSchema] = None
    paypal: Optional[PayPalSchema] = None
    crypto: Optional[CryptoSchema] = None
    billing_address: Optional[BillingAddressSchema] = None
Salin selepas log masuk
Salin selepas log masuk

Pendekatan ini menawarkan beberapa faedah penting:

  1. Hanya satu kaedah pembayaran boleh mempunyai nilai bukan nol pada satu masa.

  2. Mudah untuk melanjutkan atau mengubah suai tanpa pemindahan pangkalan data yang rumit.

  3. Memastikan integriti data pada peringkat model.

Untuk menguatkuasakan skema pada medan kaedah_bayaran kami, kami memanfaatkan model Pydantic untuk memastikan bahawa sebarang data yang dihantar ke medan itu sejajar dengan skema yang telah kami tetapkan.

from typing import Optional, Mapping, Type, NoReturn
from pydantic import ValidationError as PydanticValidationError
from django.core.exceptions import ValidationError

def payment_method_validator(value: Optional[dict]) -> Optional[Type[BaseModel] | NoReturn]:
    if value is None:
        return

    if not isinstance(value, Mapping):
        raise TypeError("Payment method must be a dictionary")

    try:
        PaymentMethodSchema(**value)
    except (TypeError, PydanticValidationError) as e:
        raise ValidationError(f"Invalid payment method: {str(e)}")
Salin selepas log masuk
Salin selepas log masuk

Di sini, kami melakukan beberapa semakan untuk memastikan data yang memasuki pengesah kami adalah jenis yang betul supaya Pydantic boleh mengesahkannya. Kami tidak melakukan apa-apa untuk nilai yang boleh dibatalkan dan kami menimbulkan ralat jenis jika nilai yang dihantar bukan subkelas jenis Pemetaan, seperti Dict atau OrderedDict.

Apabila kita mencipta contoh model Pydantic menggunakan nilai yang kita masukkan ke dalam pembina. Jika struktur nilai tidak sesuai dengan skema yang ditentukan untuk PaymentMethodSchema, Pydantic akan menimbulkan ralat pengesahan. Contohnya, jika kami menghantar nilai e-mel yang tidak sah untuk medan e-mel dalam PayPalSchema, Pydantic akan menimbulkan ralat pengesahan seperti ini:

ValidationError: 1 validation error for PaymentMethodSchema
paypal.email
  value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='Check me out on LinkedIn: https://linkedin.com/in/daniel-c-olah', input_type=str]
Salin selepas log masuk

Kami boleh menguatkuasakan pengesahan ini dalam dua cara:

  1. Kaedah Pengesahan Tersuai

    Semasa proses simpan, kami memanggil fungsi pengesahan untuk memastikan kaedah pembayaran sepadan dengan skema yang dijangkakan.

    from django.db import models
    
    class Transaction(models.Model):
        # ... other fields ...
        payment_method = models.JSONField(null=True, blank=True)
        def save(self, *args, **kwargs):
            # Override save method to include custom validation
            payment_method_validator(self.payment_method)
            super().save(*args, **kwargs)
    
    Salin selepas log masuk

    Walaupun berkesan, pendekatan ini boleh menjadi rumit dan kurang idiomatik dalam Django. Kita juga boleh menggantikan fungsi dengan kaedah kelas yang melakukan perkara yang sama untuk menjadikan kod lebih bersih.

  2. Menggunakan Pengesah Medan

    Kaedah ini memanfaatkan mekanisme pengesahan medan terbina dalam Django:

    from django.db import models
    
    class Transaction(models.Model):
        # Other relevant fields...
        payment_method = models.JSONField(default=dict, null=True, blank=True)
    
    Salin selepas log masuk
    Salin selepas log masuk

    Pendekatan ini mengimbangi fleksibiliti dan kawalan ke atas nilai yang disimpan dalam medan kaedah_pembayaran. Ia membolehkan kami menyesuaikan diri dengan perubahan masa hadapan dalam keperluan tanpa menjejaskan integriti data sedia ada dalam bidang itu. Sebagai contoh, kami boleh memasukkan medan ID Paystack dalam skema Paystack kami. Perubahan ini akan menjadi lancar, kerana kami tidak perlu berurusan dengan migrasi pangkalan data yang rumit.

Kami juga boleh menambah kaedah pay_later pada masa hadapan tanpa sebarang kerumitan. Jenis medan juga boleh berubah dan kami tidak akan menghadapi kekangan migrasi medan pangkalan data, seperti yang dihadapi semasa berhijrah daripada kunci utama integer kepada kunci utama UUID. Anda boleh menyemak kod lengkap di sini untuk memahami konsep sepenuhnya.

Denormalisasi

Denormalisasi melibatkan penduaan data yang disengajakan merentas berbilang dokumen atau koleksi untuk mengoptimumkan prestasi dan kebolehskalaan. Pendekatan ini berbeza dengan normalisasi ketat yang digunakan dalam pangkalan data hubungan tradisional, dan pangkalan data NoSQL telah memainkan peranan penting dalam mempopularkan penyahnormalan dengan memperkenalkan paradigma storan berorientasikan dokumen yang fleksibel.

Pertimbangkan senario e-dagang dengan jadual berasingan untuk produk dan pesanan. Apabila pelanggan membuat pesanan, adalah penting untuk menangkap gambar butiran produk yang disertakan dalam troli. Daripada merujuk rekod produk semasa, yang boleh berubah dari semasa ke semasa disebabkan kemas kini atau pemadaman, kami menyimpan maklumat produk terus dalam pesanan. Ini memastikan pesanan mengekalkan konteks dan integriti asalnya, mencerminkan keadaan sebenar produk pada masa pembelian. Denormalisasi memainkan peranan penting dalam mencapai konsistensi ini.

Satu pendekatan yang mungkin mungkin melibatkan penduaan beberapa medan produk dalam jadual pesanan. Walau bagaimanapun, kaedah ini boleh memperkenalkan cabaran kebolehskalaan dan menjejaskan perpaduan skema pesanan. Penyelesaian yang lebih berkesan ialah mensirikan medan produk yang berkaitan ke dalam struktur JSON, membenarkan pesanan mengekalkan rekod produk yang lengkap tanpa bergantung pada pertanyaan luaran. Kod berikut menggambarkan teknik ini:

from typing import Optional
from pydantic import BaseModel

class CreditCardSchema(BaseModel):
    last_four: str
    expiry_month: int
    expiry_year: int
    cvv: str


class PayPalSchema(BaseModel):
    email: EmailStr
    account_id: str


class CryptoSchema(BaseModel):
    wallet_address: str
    network: Optional[str] = None


class BillingAddressSchema(BaseModel):
    street: str
    city: str
    country: str
    postal_code: str
    state: Optional[str] = None


class PaymentMethodSchema(BaseModel):
    credit_card: Optional[CreditCardSchema] = None
    paypal: Optional[PayPalSchema] = None
    crypto: Optional[CryptoSchema] = None
    billing_address: Optional[BillingAddressSchema] = None
Salin selepas log masuk
Salin selepas log masuk

Memandangkan kami telah membincangkan kebanyakan konsep dalam bahagian sebelumnya, anda harus mula menghargai peranan Pydantic dalam semua ini. Dalam contoh di atas, kami menggunakan Pydantic untuk mengesahkan senarai produk yang dipautkan kepada pesanan. Dengan mentakrifkan skema untuk struktur produk, Pydantic memastikan setiap produk yang ditambahkan pada pesanan memenuhi keperluan yang dijangkakan. Jika data yang diberikan tidak mematuhi skema, Pydantic menimbulkan ralat pengesahan.

Menanyakan JSONField dalam Django

Kami boleh menanyakan kekunci JSONField dengan cara yang sama kami melakukan penampilan dalam medan Django. Berikut ialah beberapa contoh berdasarkan kes penggunaan kami.

from typing import Optional, Mapping, Type, NoReturn
from pydantic import ValidationError as PydanticValidationError
from django.core.exceptions import ValidationError

def payment_method_validator(value: Optional[dict]) -> Optional[Type[BaseModel] | NoReturn]:
    if value is None:
        return

    if not isinstance(value, Mapping):
        raise TypeError("Payment method must be a dictionary")

    try:
        PaymentMethodSchema(**value)
    except (TypeError, PydanticValidationError) as e:
        raise ValidationError(f"Invalid payment method: {str(e)}")
Salin selepas log masuk
Salin selepas log masuk

Anda boleh menyemak dokumentasi untuk mengetahui lebih lanjut tentang menapis medan JSON.

Kesimpulan

Menggunakan JSON dan JSONB dalam PostgreSQL memberikan fleksibiliti yang hebat untuk bekerja dengan data separa berstruktur dalam pangkalan data hubungan. Alat seperti Pydantic dan JSONField Django membantu menguatkuasakan peraturan untuk struktur data, menjadikannya lebih mudah untuk mengekalkan ketepatan dan menyesuaikan diri dengan perubahan. Walau bagaimanapun, fleksibiliti ini perlu digunakan dengan berhati-hati. Tanpa perancangan yang betul, ia boleh membawa kepada prestasi yang lebih perlahan atau kerumitan yang tidak perlu apabila data anda berubah dari semasa ke semasa.

Dalam Django, pengesah medan hanya dicetuskan apabila full_clean() dipanggil secara eksplisit—ini biasanya berlaku apabila menggunakan Borang Django atau memanggil is_valid() pada penyeri DRF. Untuk butiran lanjut, anda boleh merujuk kepada dokumentasi pengesah Django.

Pendekatan yang lebih maju untuk menangani perkara ini ialah melaksanakan medan Django tersuai yang menyepadukan Pydantic untuk mengendalikan kedua-dua siri dan pengesahan data JSON secara dalaman. Walaupun ini memerlukan artikel khusus, buat masa ini, anda boleh meneroka perpustakaan yang menawarkan penyelesaian siap sedia untuk masalah ini contohnya: django-pydantic-jsonfield

Atas ialah kandungan terperinci Cara Membina Model Data Fleksibel dalam Django dengan JSONField dan Pydantic. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan