Python中Pydantic的主要用法小結(jié)
Pydantic 是一個基于 Python 類型注解的數(shù)據(jù)驗(yàn)證和設(shè)置管理庫,它通過定義數(shù)據(jù)模型自動驗(yàn)證數(shù)據(jù)類型和格式,同時支持類型轉(zhuǎn)換、序列化、錯誤處理及配置管理。
1. 基礎(chǔ)模型定義
from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List
class User(BaseModel):
id: int
name: str
email: str
age: Optional[int] = None
created_at: datetime = datetime.now()
# 創(chuàng)建實(shí)例
user = User(id=1, name="張三", email="zhangsan@example.com")
print(user)
# 輸出: id=1 name='張三' email='zhangsan@example.com' age=None created_at=datetime.datetime(...)
# 訪問屬性
print(user.name) # 張三
print(user.model_dump()) # 轉(zhuǎn)換為字典2. 數(shù)據(jù)驗(yàn)證
from pydantic import BaseModel, Field, ValidationError, EmailStr
class User(BaseModel):
name: str = Field(..., min_length=2, max_length=50, description="用戶名")
age: int = Field(..., ge=0, le=150, description="年齡")
email: EmailStr # 自動驗(yàn)證郵箱格式
try:
# 無效數(shù)據(jù)
user = User(name="A", age=200, email="invalid-email")
except ValidationError as e:
print(e.json())
# 輸出詳細(xì)的驗(yàn)證錯誤信息3. 嵌套模型
from pydantic import BaseModel
from typing import List
class Address(BaseModel):
street: str
city: str
zipcode: str
class User(BaseModel):
name: str
age: int
address: Address
tags: List[str] = []
# 創(chuàng)建嵌套對象
user = User(
name="李四",
age=25,
address={"street": "中山路123號", "city": "北京", "zipcode": "100000"},
tags=["python", "developer"]
)
print(user.address.city) # 北京4. 自定義驗(yàn)證器
from pydantic import BaseModel, validator, field_validator
class Product(BaseModel):
name: str
price: float
discount: float = 0.0
@field_validator('price')
def price_must_be_positive(cls, v):
if v <= 0:
raise ValueError('價格必須大于0')
return v
@field_validator('discount')
def discount_valid(cls, v, info):
if v < 0 or v > 1:
raise ValueError('折扣必須在0-1之間')
return v
@property
def final_price(self) -> float:
"""計算最終價格"""
return self.price * (1 - self.discount)
# 使用
product = Product(name="筆記本電腦", price=5999.99, discount=0.1)
print(product.final_price) # 5399.9915. 數(shù)據(jù)轉(zhuǎn)換
from pydantic import BaseModel
from datetime import date
class Event(BaseModel):
name: str
date: date # 自動將字符串轉(zhuǎn)換為date對象
attendees: int
# 從字典創(chuàng)建
data = {
"name": "Python會議",
"date": "2024-12-25",
"attendees": "100" # 字符串會自動轉(zhuǎn)換為int
}
event = Event(**data)
print(event.date) # 2024-12-25 (date對象)
print(type(event.attendees)) # <class 'int'>6. 配置和序列化
from pydantic import BaseModel
from datetime import datetime
class User(BaseModel):
id: int
name: str
password: str
class Config:
# 從ORM對象創(chuàng)建
from_attributes = True
# 自定義字段名
alias_generator = lambda field: field.upper()
# 排除某些字段
fields = {'password': {'exclude': True}}
# 序列化時排除密碼
user = User(id=1, name="王五", password="secret123")
print(user.model_dump()) # {'id': 1, 'name': '王五'}7. 泛型支持
from pydantic import BaseModel
from typing import Generic, TypeVar, List
T = TypeVar('T')
class APIResponse(BaseModel, Generic[T]):
code: int
message: str
data: T
# 使用
class User(BaseModel):
id: int
name: str
# 單個用戶響應(yīng)
response = APIResponse[User](
code=200,
message="success",
data={"id": 1, "name": "張三"}
)
# 用戶列表響應(yīng)
response_list = APIResponse[List[User]](
code=200,
message="success",
data=[{"id": 1, "name": "張三"}, {"id": 2, "name": "李四"}]
)8. 實(shí)際應(yīng)用場景:FastAPI集成
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class UserCreate(BaseModel):
username: str = Field(..., min_length=3, max_length=20)
email: str
password: str = Field(..., min_length=8)
@app.post("/users/")
async def create_user(user: UserCreate):
# 自動驗(yàn)證請求數(shù)據(jù)
return {"message": f"用戶 {user.username} 創(chuàng)建成功"}9. 高級特性:遞歸模型
from pydantic import BaseModel
from typing import List, Optional
class Category(BaseModel):
id: int
name: str
children: List['Category'] = [] # 自引用
class Config:
# 允許自引用
arbitrary_types_allowed = True
# 創(chuàng)建樹形結(jié)構(gòu)
root = Category(
id=1,
name="電子產(chǎn)品",
children=[
Category(id=2, name="手機(jī)", children=[]),
Category(id=3, name="電腦", children=[
Category(id=4, name="筆記本", children=[]),
Category(id=5, name="臺式機(jī)", children=[])
])
]
)10. 環(huán)境變量支持
from pydantic_settings import BaseSettings
from typing import Optional
class Settings(BaseSettings):
app_name: str = "MyApp"
database_url: str
debug: bool = False
api_key: Optional[str] = None
class Config:
env_file = ".env" # 從.env文件讀取環(huán)境變量
# 使用
settings = Settings()
print(settings.database_url) # 從環(huán)境變量或.env文件讀取Pydantic的主要優(yōu)勢:
- 類型安全:自動進(jìn)行類型檢查和轉(zhuǎn)換
- 數(shù)據(jù)驗(yàn)證:豐富的驗(yàn)證器
- IDE友好:完整的類型提示支持
- 性能優(yōu)異:基于Python類型提示,性能好
- 易于集成:與FastAPI等框架無縫集成
這些例子展示了Pydantic的主要特性,實(shí)際開發(fā)中可以根據(jù)需求靈活使用。
我來詳細(xì)解釋第6部分的"配置和序列化"代碼:
Config基礎(chǔ)概念
在Pydantic中,Config類是用來配置模型行為的特殊內(nèi)部類。
1. 基本模型
from pydantic import BaseModel
from datetime import datetime
class User(BaseModel):
id: int
name: str
password: str
# 創(chuàng)建用戶
user = User(id=1, name="王五", password="secret123")
# 默認(rèn)序列化:所有字段都會輸出
print(user.model_dump())
# 輸出: {'id': 1, 'name': '王五', 'password': 'secret123'}
2. 添加Config配置
class User(BaseModel):
id: int
name: str
password: str
class Config:
# 1. from_attributes = True
from_attributes = True
# 2. alias_generator = lambda field: field.upper()
alias_generator = lambda field: field.upper()
# 3. fields = {'password': {'exclude': True}}
fields = {'password': {'exclude': True}}
現(xiàn)在我來詳細(xì)解釋每個配置項:
配置1:from_attributes = True
這個配置允許從其他對象創(chuàng)建Pydantic模型實(shí)例,比如從數(shù)據(jù)庫ORM對象:
# 假設(shè)有一個SQLAlchemy的User模型
class SQLAlchemyUser:
def __init__(self, id, name, password):
self.id = id
self.name = name
self.password = password
# 創(chuàng)建ORM對象
db_user = SQLAlchemyUser(id=1, name="趙六", password="pass456")
# 沒有from_attributes = True時,這樣會報錯
# user = User.model_validate(db_user) # 錯誤!
# 有了from_attributes = True,就可以直接從ORM對象創(chuàng)建
user = User.model_validate(db_user) # 正確!
print(user.name) # 輸出: 趙六
實(shí)際應(yīng)用場景:
# 從數(shù)據(jù)庫查詢出來的對象 db_user = db.query(User).first() # 這是一個SQLAlchemy對象 # 直接轉(zhuǎn)換為Pydantic模型用于API響應(yīng) pydantic_user = User.model_validate(db_user)
配置2:alias_generator = lambda field: field.upper()
這個配置定義了字段別名生成規(guī)則。upper()表示將字段名轉(zhuǎn)換為大寫:
class User(BaseModel):
id: int
name: str
password: str
class Config:
alias_generator = lambda field: field.upper()
# 創(chuàng)建對象時可以使用大寫字段名
user = User(ID=1, NAME="王五", PASSWORD="secret123")
# 雖然字段名是小寫的,但可以用大寫傳入
print(user.id) # 1
print(user.name) # 王五
# 序列化時也會使用別名
print(user.model_dump(by_alias=True))
# 輸出: {'ID': 1, 'NAME': '王五', 'PASSWORD': 'secret123'}
print(user.model_dump())
# 輸出: {'id': 1, 'name': '王五', 'password': 'secret123'} # 默認(rèn)還是原字段名
實(shí)際應(yīng)用場景:處理不同命名規(guī)范的API(例如,Python使用小寫,但API使用大寫或駝峰)
# 處理使用駝峰命名的API
class User(BaseModel):
user_id: int
user_name: str
class Config:
alias_generator = lambda field: ''.join(
word.capitalize() if i > 0 else word
for i, word in enumerate(field.split('_'))
) # 轉(zhuǎn)換為駝峰: user_name -> userName
# 現(xiàn)在可以接收駝峰格式的數(shù)據(jù)
user = User(userId=1, userName="張三") # 使用駝峰
配置3:fields = {'password': {'exclude': True}}
這個配置指定在序列化時排除某些字段:
class User(BaseModel):
id: int
name: str
password: str
class Config:
fields = {'password': {'exclude': True}}
user = User(id=1, name="王五", password="secret123")
# 序列化時自動排除password字段
print(user.model_dump())
# 輸出: {'id': 1, 'name': '王五'}
# 注意:password被排除了
# 即使想包含password也包含不了
print(user.model_dump(exclude={'password': False})) # 依然沒有password
完整示例對比
from pydantic import BaseModel
# 無配置版本
class UserSimple(BaseModel):
id: int
name: str
password: str
# 完整配置版本
class UserConfigured(BaseModel):
id: int
name: str
password: str
class Config:
from_attributes = True
alias_generator = lambda field: field.upper()
fields = {'password': {'exclude': True}}
# 演示對比
print("=== 簡單版本 ===")
user1 = UserSimple(id=1, name="張三", password="123")
print(user1.model_dump()) # {'id': 1, 'name': '張三', 'password': '123'}
print("\n=== 配置版本 ===")
# 1. 可以使用大寫別名
user2 = UserConfigured(ID=1, NAME="李四", PASSWORD="456")
print(user2.name) # 李四
# 2. 序列化時排除password
print(user2.model_dump()) # {'id': 1, 'name': '李四'}
# 3. 可以輸出帶別名的版本
print(user2.model_dump(by_alias=True)) # {'ID': 1, 'NAME': '李四'}
print("\n=== 從ORM對象創(chuàng)建 ===")
class ORMUser:
def __init__(self, id, name, password):
self.id = id
self.name = name
self.password = password
# 從ORM對象直接創(chuàng)建
orm_user = ORMUser(id=3, name="王五", password="789")
pydantic_user = UserConfigured.model_validate(orm_user)
print(pydantic_user.model_dump()) # {'id': 3, 'name': '王五'}
# password字段被自動排除其他常用Config配置
class User(BaseModel):
id: int
name: str
email: str
class Config:
# 1. 允許額外字段
extra = "allow" # 或 "forbid"(禁止)或 "ignore"(忽略)
# 2. 設(shè)置JSON編碼器
json_encoders = {
datetime: lambda v: v.isoformat()
}
# 3. 驗(yàn)證賦值
validate_assignment = True # 賦值時重新驗(yàn)證
# 4. 標(biāo)題
title = "User Model"
總結(jié)
這個示例展示了Pydantic的三個重要配置:
- from_attributes = True:讓模型可以從其他Python對象(如數(shù)據(jù)庫ORM對象)創(chuàng)建
- alias_generator:自動生成字段別名,用于處理不同命名規(guī)范的輸入輸出
- fields = {'password': {'exclude': True}}:永久排除敏感字段(如密碼),防止意外泄露
這些配置讓Pydantic模型更加靈活和安全,特別適合在實(shí)際項目中使用。
到此這篇關(guān)于Python中Pydantic的主要用法小結(jié)的文章就介紹到這了,更多相關(guān)Pydantic 用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python-for循環(huán)的內(nèi)部機(jī)制
這篇文章主要介紹了Python for循環(huán)的內(nèi)部機(jī)制,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06
PyPDF2讀取PDF文件內(nèi)容保存到本地TXT實(shí)例
這篇文章主要介紹了PyPDF2讀取PDF文件內(nèi)容保存到本地TXT實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Python?Streamlit制作交互式可視化網(wǎng)頁應(yīng)用實(shí)例
這篇文章主要為大家介紹了Python?Streamlit制作交互式可視化網(wǎng)頁應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Windows下將Python文件打包成.EXE可執(zhí)行文件的方法
這篇文章主要介紹了Windows下將Python文件打包成.EXE可執(zhí)行文件的方法,需要的朋友可以參考下2018-08-08
Python?Decorator裝飾器的創(chuàng)建方法及常用場景分析
這篇文章主要介紹了Python?Decorator裝飾器的創(chuàng)建方法及常用場景,裝飾器可以分成方法裝飾器和類裝飾器,他們的區(qū)別是一個是用函數(shù)實(shí)現(xiàn)的裝飾器,一個是用類實(shí)現(xiàn)的裝飾器,他們也都能在方法和類上進(jìn)行裝飾,需要的朋友可以參考下2022-07-07
使用python裝飾器計算函數(shù)運(yùn)行時間的實(shí)例
下面小編就為大家分享一篇使用python裝飾器計算函數(shù)運(yùn)行時間的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04
解決Python報錯ValueError list.remove(x) x not&nbs
文章討論了在Python開發(fā)過程中遇到的列表移除元素時出現(xiàn)的"list.remove(x): x not in list"錯誤,文章首先解釋了錯誤的原因,特別是在循環(huán)中使用remove方法時,然后,文章通過幾個例子展示了這種錯誤的情況,并解釋了為什么會出現(xiàn)這樣的結(jié)果2024-11-11

