在本文中,我将引导您了解如何使用 Django 的 JSONField(JSON 和 JSONB 包装器)对半结构化数据进行建模,以及如何对其强制实施架构使用 Pydantic 获取数据——对于 Python Web 开发人员来说,这种方法应该很自然。
灵活的类型定义
让我们考虑一个处理支付的系统,例如交易表。它看起来像这样:
from django.db import models class Transaction(models.Model): # Other relevant fields... payment_method = models.JSONField(default=dict, null=True, blank=True)
我们的重点是 payment_method 字段。在现实世界中,我们将拥有处理付款的现有方法:
信用卡
PayPal
现在购买,稍后付款
加密货币
我们的系统必须能够适应存储每种付款方式所需的特定数据,同时保持一致且可验证的结构。
我们将使用 Pydantic 为不同的付款方式定义精确的模式:
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
这种方法有几个显着的好处:
一次只能有一种付款方式具有非空值。
无需复杂的数据库迁移即可轻松扩展或修改。
确保模型级别的数据完整性。
为了在 payment_method 字段上强制执行架构,我们利用 Pydantic 模型来确保传递到该字段的任何数据都与我们定义的架构一致。
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)}")
在这里,我们执行一些检查,以确保输入验证器的数据类型正确,以便 Pydantic 可以验证它。我们对可为 null 的值不执行任何操作,如果传入的值不是 Mapping 类型的子类(例如 Dict 或 OrderedDict),则会引发类型错误。
当我们使用传递给构造函数的值创建 Pydantic 模型的实例时。如果值的结构不符合 PaymentMethodSchema 定义的架构,Pydantic 将引发验证错误。例如,如果我们在 PayPalSchema 中为电子邮件字段传递无效的电子邮件值,Pydantic 将引发如下验证错误:
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]
我们可以通过两种方式强制执行此验证:
-
自定义验证方法
在保存过程中,我们调用验证函数以确保付款方式与预期模式匹配。
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)
虽然有效,但这种方法在 Django 中可能会变得麻烦且不太惯用。我们甚至可以用具有相同功能的类方法替换该函数,以使代码更简洁。
-
使用字段验证器
此方法利用了 Django 内置的字段验证机制:
from django.db import models class Transaction(models.Model): # Other relevant fields... payment_method = models.JSONField(default=dict, null=True, blank=True)
这种方法平衡了灵活性和对 payment_method 字段中存储的值的控制。它使我们能够适应未来需求的变化,而不会损害该领域现有数据的完整性。例如,我们可以在 Paystack 架构中包含 Paystack ID 字段。此更改将是无缝的,因为我们不必处理复杂的数据库迁移。
我们甚至可以在未来添加 pay_later 方法,没有任何麻烦。字段的类型也可能会发生变化,并且我们不会面临数据库字段迁移限制,就像从整数主键迁移到 UUID 主键时遇到的限制一样。您可以在此处查看完整的代码以完全理解这个概念。
非规范化
反规范化涉及跨多个文档或集合故意复制数据,以优化性能和可扩展性。这种方法与传统关系数据库中使用的严格规范化形成鲜明对比,NoSQL 数据库通过引入灵活的、面向文档的存储范例,在普及非规范化方面发挥了重要作用。
考虑一个电子商务场景,其中产品和订单有单独的表。当客户下订单时,必须捕获购物车中产品详细信息的快照。我们不会引用当前的产品记录(该记录可能会随着时间的推移因更新或删除而发生变化),而是直接将产品信息存储在订单中。这可确保订单保留其原始上下文和完整性,反映购买时产品的确切状态。非规范化在实现这种一致性方面发挥着至关重要的作用。
一种可能的方法可能涉及复制订单表中的某些产品字段。然而,这种方法可能会带来可扩展性挑战并损害订单模式的内聚性。更有效的解决方案是将相关产品字段序列化为 JSON 结构,让订单能够维护产品的独立记录,而不需要依赖外部查询。下面的代码说明了这种技术:
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
由于我们已经介绍了上一节中的大部分概念,您应该开始欣赏 Pydantic 在这一切中的作用。在上面的示例中,我们使用 Pydantic 来验证链接到订单的产品列表。通过定义产品结构的模式,Pydantic 确保添加到订单中的每个产品都满足预期要求。如果提供的数据不符合架构,Pydantic 会引发验证错误。
在 Django 中查询 JSONField
我们可以像在 Django 字段中执行查找一样查询 JSONField 键。以下是基于我们的用例的一些示例。
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)}")
您可以查看文档以了解有关过滤 JSON 字段的更多信息。
结论
在 PostgreSQL 中使用 JSON 和 JSONB 为处理关系数据库中的半结构化数据提供了极大的灵活性。 Pydantic 和 Django 的 JSONField 等工具有助于强制执行数据结构规则,从而更容易保持准确性并适应变化。然而,这种灵活性需要谨慎使用。如果没有适当的规划,随着数据随着时间的推移而变化,可能会导致性能下降或不必要的复杂性。
在 Django 中,仅当显式调用 full_clean() 时才会触发字段验证器 - 这通常发生在使用 Django Forms 或在 DRF 序列化器上调用 is_valid() 时。更多详细信息,您可以参考 Django 验证器文档。
解决此问题的更高级方法是实现一个自定义 Django 字段,该字段集成 Pydantic 以在内部处理 JSON 数据的序列化和验证。虽然这需要一篇专门的文章,但目前,您可以探索为该问题提供现成解决方案的库,例如:django-pydantic-jsonfield
以上是如何使用 JSONField 和 Pydantic 在 Django 中构建灵活的数据模型的详细内容。更多信息请关注PHP中文网其他相关文章!

SlicingaPythonlistisdoneusingthesyntaxlist[start:stop:step].Here'showitworks:1)Startistheindexofthefirstelementtoinclude.2)Stopistheindexofthefirstelementtoexclude.3)Stepistheincrementbetweenelements.It'susefulforextractingportionsoflistsandcanuseneg

numpyallowsforvariousoperationsonArrays:1)basicarithmeticlikeaddition,减法,乘法和division; 2)evationAperationssuchasmatrixmultiplication; 3)element-wiseOperations wiseOperationswithOutexpliitloops; 4)

Arresinpython,尤其是Throughnumpyandpandas,weessentialFordataAnalysis,offeringSpeedAndeffied.1)NumpyArseNable efflaysenable efficefliceHandlingAtaSetSetSetSetSetSetSetSetSetSetSetsetSetSetSetSetsopplexoperationslikemovingaverages.2)

列表sandnumpyArraysInpyThonHavedIfferentMemoryfootprints:listSaremoreFlexibleButlessMemory-效率,而alenumpyArraySareSareOptimizedFornumericalData.1)listsStorReereReereReereReereFerenceStoObjects,withoverHeadeBheadaroundAroundaroundaround64bytaround64bitson64-bitsysysysyssyssyssyssyssyssysssys2)

toensurepythonscriptsbehavecorrectlyacrycrossdevelvermations,登台和生产,USETHESTERTATE:1)Environment varriablesforsimplesettings,2)configurationFilesForefilesForcomPlexSetups,3)dynamiCofforAdaptapity.eachmethodofferSuniquebeneiquebeneiquebeneniqueBenefitsaniqueBenefitsandrefitsandRequiresandRequireSandRequireSca

Python列表切片的基本语法是list[start:stop:step]。1.start是包含的第一个元素索引,2.stop是排除的第一个元素索引,3.step决定元素之间的步长。切片不仅用于提取数据,还可以修改和反转列表。

ListSoutPerformarRaysin:1)DynamicsizicsizingandFrequentInsertions/删除,2)储存的二聚体和3)MemoryFeliceFiceForceforseforsparsedata,butmayhaveslightperformancecostsinclentoperations。

toConvertapythonarraytoalist,usEthelist()constructororageneratorexpression.1)intimpthearraymoduleandcreateanArray.2)USELIST(ARR)或[XFORXINARR] to ConconverTittoalist,请考虑performorefformanceandmemoryfformanceandmemoryfformienceforlargedAtasetset。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。