部分源码
python
class BaseModel(metaclass=_model_construction.ModelMetaclass):
"""!!! abstract "Usage Documentation"
[Models](../concepts/models.md)
A base class for creating Pydantic models.
Attributes:
__class_vars__: The names of the class variables defined on the model.
__private_attributes__: Metadata about the private attributes of the model.
__signature__: The synthesized `__init__` [`Signature`][inspect.Signature] of the model.
__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models.
The `origin` and `args` items map to the [`__origin__`][genericalias.__origin__]
and [`__args__`][genericalias.__args__] attributes of [generic aliases][types-genericalias],
and the `parameter` item maps to the `__parameter__` attribute of generic classes.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.
__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.
__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
"""
__pydantic_fields__: ClassVar[Dict[str, FieldInfo]] # noqa: UP006
"""A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
This replaces `Model.__fields__` from Pydantic V1.
"""
__pydantic_extra__: Dict[str, Any] | None = _model_construction.NoInitField(init=False) # noqa: UP006
"""A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] is set to `'allow'`."""
元类机制
AI回答: 与普通 Python 类不同,BaseModel 使用自定义元类 ModelMetaclass。当你的子类被定义时,元类会在解释器读取类体的那一刻,自动收集所有的类型注解(annotations ),并生成对应的核心数据结构(CoreSchema)。 这就是 Pydantic 性能强悍的第一个秘密:大量工作前置到类定义阶段完成,实例化时只需调用已编译好的 Rust 验证器。
核心验证
python
__pydantic_core_schema__: ClassVar[CoreSchema]
__pydantic_serializer__: ClassVar[SchemaSerializer] # SchemaValidator:负责实例化时的数据校验与强制转换。
__pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] # chemaSerializer:负责高速地序列化为 Python 字典或 JSON。
这是 V2 与 V1 最大的架构变化 。在 Pydantic V1 中,验证逻辑全由 Python 编写,速度较慢。V2 中,元类首先把你的模型声明编译成 CoreSchema,然后交给由 Rust 编写的 pydantic-core 库
字段与状态
__pydantic_fields__:存储了模型中所有字段的元信息(默认值、是否必填、别名等),由元类在定义阶段填充。__pydantic_fields_set__:至关重要 。它记录了实例化时你显式传递了哪些字段 。这能精确区分"未传值"与"主动传了None",在处理 PATCH 操作或部分更新时极其有用。__pydantic_extra__:当模型配置了extra='allow',所有未定义的额外字段会被安全收纳到这里,不至于丢失数据。
学习例子
基础
- 基础访问数据:
python
from typing import *
from pydantic import BaseModel, ValidationError, ConfigDict, Field
class User(BaseModel):
age: int
name:
try:
user2 = User(age="10000", name="ak") # 不会报错,原因:Pydantic默认为宽松模式,内置类型强制转换,尽量转数据类型
print(f"{type(user2.age)}")
except ValidationError as e:
print(f"发生报错:{e}")
- 防止字段隐式转换:
python
from pydantic import BaseModel, ValidationError, ConfigDict, Field
class User(BaseModel):
model_config = ConfigDict(strict=True) # 所有字段开启严格校验
age: int
name: str
class User(BaseModel):
age: int = Field(strict=True) # 指明这个字段拒绝隐式转换
name: str
- 序列化与反序列化:
python
# 序列化
dict_1 = user1.model_dump()
json_1 = user1.model_dump_json()
print(f"dict_1={dict_1} \n json_1={json_1}")
#dict_1={'age': 20, 'name': 'AK'}
# json_1={"age":20,"name":"AK"}
# 反序列化
new_User = User.model_validate_json(json_1)
print(new_User) # 打印输出:age=20 name='AK'
- 增加字段、查看原有字段
python
class User(BaseModel):
model_config = ConfigDict(extra="allow") # 允许增加字段
age: int
name: str
user1 = User(name="AK", age=20, color="blue")
print(f"显示传递:{user1.__pydantic_fields_set__} \t 未定义字段:{user1.__pydantic_extra__}")
# 打印输出:显示传递:{'color', 'age', 'name'} 未定义字段:{'color': 'blue'}
进阶
- 增加字段复杂度,如嵌套数据
python
class Item(BaseModel):
name: str
price: float
class Order(BaseModel):
order_id: str
items: List[Item] # 包含多个Item对象的列表
status: Tuple[str, str] # 元组:(订单状态, 配送状态)
order_data = {
'order_id': "741239478921",
'items': [
{'name': "Laptop", 'price': 100.1},
{'name': "Mouse", 'price': 49.9}
],
'status': ("Paid", "Shipped")
}
order = Order(**order_data) # 通过字典,然后解包**,实例化对象
print(f"order= {order}")
- 模型继承,共享相同字段
python
class Base1(BaseModel):
a: str
b: str
c: str
class Test_Base1(Base1):
price: int
te = Test_Base1(a="", b="", c="", price=10)
print(te) # a='' b='' c='' price=10
- 树形递归结构
python
class Department(BaseModel):
id: int
name: str
children: Optional[List['Department']] = None # 递归类型注解:子节点依然是 Department 对象的列表
# 传入嵌套字典,自动解析为树形对象
dept_data = {
"id": 1, "name": "总公司",
"children": [
{"id": 2, "name": "研发部", "children": None},
{"id": 3, "name": "市场部", "children": [
{"id": 4, "name": "华南区", "children": None}
]}
]
}
dept = Department(**dept_data)
print(dept)
# id=1 name='总公司' children=[Department(id=2, name='研发部', children=None), Department(id=3, name='市场部', children=[Department(id=4, name='华南区', children=None)])]
- 字段约束
python
from typing import Annotated
class Product(BaseModel):
name: str = Field(min_length=2, max_length=10)
price: Annotated[float, Field(..., ge=0, description="产品价格")]
price2: float = Field(..., ge=0, description="产品价格")
- 自定义业务逻辑校验
python
from pydantic import field_validator, model_validator
class Item(BaseModel):
name: str
price: float
class OrderInfo(BaseModel):
user_email:str
items: List[Item]
total_amount: float
# 验证字段user_email,确保邮箱含有字符@
@field_validator('user_email')
@classmethod
def validate_email(cls, value:str) -> str:
if '@' not in value:
raise ValidationError("Email must contain "@" symbol")
return value
# 跨字段校验
@model_validator(mode='after')
def check_total_amout(self) -> 'OrderInfo':
# 自定义策略
if self.items and self.total_amount is not None:
total_price = sum( item.price for item in self.items)
if total_price > self.total_amount:
raise ValueError('Total amount cannot be less than the sum of item prices.')
return self
validate_email()函数的逻辑:实例化类OrderInfo时,仅对字段user_email进行校验。 必须使用 @classmethod,第一个参数是 cls(代表类本身),第二个参数 value 是传入的邮箱字符串。
check_total_amout()函数的逻辑:
- 触发时机 :在所有字段(包括
user_email和items)都完成基础校验和转换之后执行。 mode='after':这是 Pydantic V2 的语法,表示在所有字段解析完成后执行。self参数 :注意这里没有@classmethod,它是一个实例方法。因为此时模型已经初步构建,你可以直接通过self.items和self.total_amount访问已转换好的对象属性。