Гузариш ба мундариҷа
Мавзӯи 3 аз 6

Моделҳои Pydantic

Чаро моделҳо лозиманд

Ҳангоми сохтани сабт муштарӣ якбора чанд қимат мефиристад: ном, миқдор ва парчам. Дастӣ санҷидани ҳар кадом душвор аст: сатри холиро фаромӯш кардан, навъро омехтан ё қоидаро дар як масир дигар кардан осон аст. Модели Pydantic шакли додаҳоро дар як ҷой муайян карда, шартномаи вуруди API мешавад.

Танаи дархост додаҳои пас аз сарлавҳаҳои HTTP аст; дар ин ҷо JSON истифода мекунем. Модел луғати вурудро ба объекте бо майдонҳои санҷидашуда табдил медиҳад. Дар курс Pydantic 2 истифода мешавад: луғатро бо model_dump() мегирем. Ҳар мисоли поёнро алоҳида иҷро кунед.

Майдонҳо, ҳатмӣ будан ва маҳдудиятҳо

Синфи вориси BaseModel майдонҳоро тавсиф мекунад. Майдони бе қимати пешфарз ҳатмӣ аст; Field ҳудудҳо меафзояд. min_length ва max_length дарозии сатрро, ge ва le ададро бо дохил кардани ҳудудҳо маҳдуд мекунанд. Сатри ададии мувофиқ метавонад ба адад табдил ёбад: санҷиши одӣ ҳамаи табдилҳоро манъ намекунад.

from pydantic import BaseModel, Field, ValidationError

class Parcel(BaseModel):
    label: str = Field(min_length=2, max_length=8)
    weight: int = Field(2, ge=1, le=9)

p = Parcel(label="AB", weight="4")
print(p.model_dump())
try:
    Parcel(label="A")
except ValidationError as exc:
    print(exc.errors()[0]["loc"], exc.errors()[0]["type"])

Баромад:

{'label': 'AB', 'weight': 4}
('label',) string_too_short

JSON ба аргументи функсия табдил меёбад

FastAPI параметри навъи моделро аз танаи дархост мехонад. Аргументи json= дар TestClient.post JSON ва Content-Type-и мувофиқро месозад. Дар коркардкунанда майдонҳо ҳамчун атрибут дастрасанд. Вуруди нодуруст 422 мегирад ва коркардкунанда оғоз намешавад: ҳисобкунаки даъватҳо инро нишон медиҳад. status_code=201 рамзи сохтани муваффақро медиҳад.

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

class Parcel(BaseModel):
    label: str = Field(min_length=2)

app = FastAPI()
calls = []

@app.post("/parcels", status_code=201)
def create(parcel: Parcel):
    calls.append(parcel.label)
    return parcel.model_dump()

client = TestClient(app)
r = client.post("/parcels", json={"label": "AB"})
print(r.status_code, r.json())
print(client.post("/parcels", json={}).status_code)
print(len(calls))

Баромад:

201 {'label': 'AB'}
422
1

Модели ҷудои ҷавоб

Нигоҳдории дохилӣ ва ҷавоби оммавӣ вазифаҳои гуногун доранд. response_model танҳо майдонҳои эълоншударо нигоҳ дошта, месанҷад. Дар мисол токени дохилӣ ба муштарӣ намерасад. Агар худи сервер додаҳои ба модел номувофиқ баргардонад, ин хатои татбиқи ҷавоб аст, на хатои 422-и вуруд. Схемаи ҷавоб дар /docs ҳам пайдо мешавад.

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel

class ParcelOut(BaseModel):
    id: int
    label: str

app = FastAPI()

@app.get("/parcel", response_model=ParcelOut)
def read():
    return {"id": 4, "label": "AB", "internal_token": "xyz"}

r = TestClient(app).get("/parcel")
print(r.json())
print("internal_token" in r.json())

Баромад:

{'id': 4, 'label': 'AB'}
False

Майдон фиристода шуд ё не?

Навсозии қисмиро одатан бо PATCH иҷро мекунанд. Барои он майдонҳои партофташаванда ва роҳи фарқ кардани нафиристодан аз null-и ошкор лозиманд. model_dump(exclude_unset=True) танҳо майдонҳои дар вуруд набударо хориҷ мекунад. exclude_none=True вазифаи дигар дорад: ҳамаи None-ро, ҳатто ошкоро фиристодашударо, хориҷ мекунад. Фарқро бе тағйири анбор мебинем.

from pydantic import BaseModel

class ParcelPatch(BaseModel):
    label: str | None = None
    urgent: bool | None = None

patch = ParcelPatch(urgent=False)
print(patch.model_dump())
print(patch.model_dump(exclude_unset=True))
explicit = ParcelPatch(label=None)
print(explicit.model_dump(exclude_unset=True))
print(explicit.model_dump(exclude_none=True))

Баромад:

{'label': None, 'urgent': False}
{'urgent': False}
{'label': None}
{}

Дар дохил чӣ рӯй медиҳад

Модел ба санҷиши пурсишнома монанд аст: аввал мавҷудияти майдонҳои ҳатмӣ ва навъҳо, сипас маҳдудиятҳо санҷида мешаванд. Пас аз санҷиши муваффақ объекти модел пайдо мешавад. FastAPI ин санҷишро аз аннотатсияи параметр сохта, баъд масирро даъват мекунад ва ҷавобашро алоҳида коркард менамояд. Модели вуруд додаҳои иҷозатшудаи муштарӣ ва модели баромад ваъдаи сервер ба муштариро тавсиф мекунад.

Қимати пешфарз ҳангоми набудани майдон истифода мешавад. Ин маънои «ҳар қимати нодурустро иваз кардан»-ро надорад: null-и ошкор навъи мувофиқ, масалан str | None, талаб мекунад. Сатри танҳо аз фосилаҳо иборат ба min_length=1 мувофиқ аст, зеро фосила ҳам аломат мебошад; меъёрсозии матнро алоҳида тарҳрезӣ кунед. Ба нигоҳ доштани майдонҳои зиёдатии вуруд такя накунед: модели одӣ онҳоро бо пешфарз нодида мегирад.

Хатоҳои маъмул ва ислоҳи онҳо

  1. weight: int бе = 2 майдонро ҳатмӣ мекунад: дархости бе он 422 мегирад. Агар нафиристодан иҷозат бошад, пешфарзи дуруст илова кунед.
  2. label: str | None ба null иҷозат медиҳад, вале бе = None нафиристоданро иҷозат намедиҳад. Барои майдони ғайриҳатмӣ ҳам навъ ва ҳам пешфарз гузоред.
  3. return parcel.model_dump истинод ба методро бармегардонад. Онро даъват кунед: parcel.model_dump().
  4. patch.model_dump() пешфарзҳои нафиристодаро низ дар бар мегирад. Барои PATCH exclude_unset=True истифода кунед; агар null-и ошкор муҳим бошад, онро бо exclude_none=True иваз накунед.

Ёддошт

Амал Восита
Тавсифи сохтор class X(BaseModel)
Маҳдуд кардани майдон Field(min_length=..., ge=...)
Гирифтани луғат obj.model_dump()
Қабули JSON параметри навъи модел
Филтр кардани ҷавоб response_model=ModelOut
Гирифтани танҳо майдонҳои фиристода model_dump(exclude_unset=True)