Ачааллж байна...
Түвшин 1-ийн төгсгөлд бид хоёр дутагдлыг нэрлэсэн. Таны API зөвхөн уншиж чаддаг; шинэ өгөгдөл хүлээж авч чаддаггүй. Хүлээж авах юм бол түүнийг шалгах арга байхгүй.
Энэ хоёр асуудал үнэндээ нэг асуудал юм. Өгөгдөл хүлээж авах гэдэг нь итгэх гэсэн үг. Гадаад ертөнцөөс ирсэн зүйлд итгэх нь программ хангамжийн хамгийн эрсдэлтэй мөч бөгөөд түүнийг хэрхэн зохицуулах вэ гэдэг нь backend хөгжүүлэлтийн үндсэн асуулт юм.
Pydantic бол тэр асуултын хариу юм. Энэ хичээлд бид код бага бичнэ. Оронд нь Pydantic яагаад оршдог, ямар асуудлыг шийддэг, Курс 2-ын мэдлэгтэй тань хэрхэн холбогддогийг ойлгоно. Дараагийн хичээлээс эхлэн бид түүнийг өдөр бүр ашиглана.
Шинэ хот нэмэх endpoint бичих ёстой гэж бодъё. Хэрэглэгч бидэнд ийм өгөгдөл илгээнэ:
json
{
"name": "Сүхбаатар",
"province": "Сэлэнгэ",
"population": 22000,
"founded": 1940,
"is_capital": false
}Сайхан. Гэхдээ хэрэглэгч үргэлж ингэж эелдэг байхгүй. Тэд ийм зүйл ч илгээж болно:
json
{
"name": "Сүхбаатар",
"population": "маш их"
}province дутуу. population нь тоо биш текст. founded алга. is_capital алга.
Эсвэл ийм:
json
{
"name": "",
"province": "Сэлэнгэ",
"population": -500,
"founded": 3000,
"is_capital": "магадгүй"
}Нэр хоосон. Хүн ам сөрөг. Он ирээдүйд. is_capital нь bool биш.
Эсвэл огт өөр зүйл:
json
{
"hello": "world"
}Эдгээр бүх тохиолдлыг та зохицуулах ёстой. Хэрэв зохицуулахгүй бол таны программ унана (500), эсвэл бүр муу — утгагүй өгөгдлийг хадгална. Хоёр дахь нь илүү аюултай, учир нь тэр өгөгдөл тань удаан хугацаанд систем дотор явж, хожим огт өөр газар асуудал үүсгэдэг.
Pydantic-гүйгээр энэ ажлыг хэрхэн хийхийг харъя. Энэ код бол бидний бичихгүй код, гэхдээ түүнийг харах нь Pydantic-ийн үнэ цэнийг ойлгуулна.
python
@app.post("/cities")
def create_city(data: dict):
# name шалгах
if "name" not in data:
raise HTTPException(400, "name талбар заавал")
if not isinstance(data["name"], str):
raise HTTPException(400, "name нь текст байх ёстой")
if len(data["name"]) == 0:
raise HTTPException(400, "name хоосон байж болохгүй")
# province шалгах
if "province" not in data:
raise HTTPException(400, "province талбар заавал")
if not isinstance(data["province"], str):
raise HTTPException(400, "province нь текст байх ёстой")
# population шалгах
if "population" not in data:
raise HTTPException(400, "population талбар заавал")
if not isinstance(data["population"], int):
raise HTTPException(400, "population нь тоо байх ёстой")
if data["population"] < 0:
raise HTTPException(400, "population сөрөг байж болохгүй")
# founded шалгах
if "founded" not in data:
raise HTTPException(400, "founded талбар заавал")
if not isinstance(data["founded"], int):
raise HTTPException(400, "founded нь тоо байх ёстой")
# is_capital шалгах
if "is_capital" not in data:
raise HTTPException(400, "is_capital талбар заавал")
if not isinstance(data["is_capital"], bool):
raise HTTPException(400, "is_capital нь bool байх ёстой")
# эцэст нь жинхэнэ ажил
cities.append(data)
return dataХорин таван мөр шалгалт. Нэг жинхэнэ ажлын мөр.
Одоо асуултууд гарч ирнэ. Хэрэв шинэ талбар нэмбэл? Дахиад дөрвөн мөр. Хэрэв ижил шалгалтыг өөр endpoint дээр (жишээ нь хот засах PUT дээр) хийх бол? Бүгдийг хуулна. Хэрэв нэг газар алдаа гарвал? Бусад газар нь хуучин хэвээр үлдэнэ.
Хамгийн муу нь: энэ код нь эхний алдаан дээр зогсдог. Хэрэглэгч гурван талбар буруу бичсэн бол эхнийхийг л мэдэж, засаад дахин илгээж, дараагийнхыг мэдэж, дахин засаж... Уйтгартай.
Мөн /docs хуудас юу ч харуулахгүй. data: dict гэдэг нь "ямар нэг dictionary" гэсэн үг; ямар талбар шаардлагатайг баримт бичиг мэдэхгүй.
Энэ бол бидний зайлсхийх ёстой код.
Дээрх хорин таван мөрийг Pydantic-аар бичвэл ийм болно:
python
from pydantic import BaseModel
class City(BaseModel):
name: str
province: str
population: int
founded: int
is_capital: boolТаван мөр. Шалгалт алга. if алга. raise алга.
Гэхдээ энэ таван мөр нь дээрх хорин тавыг бүгдийг хийнэ, бүр илүүг ч хийнэ. Талбар дутуу бол барина. Төрөл буруу бол барина. Бүх алдааг нэг дор мэдээлнэ. Дэлгэрэнгүй JSON хариу үүсгэнэ. /docs дээр бүрэн маягт харуулна.
Хэрхэн? Учир нь та юу байх ёстойг зарласан. Pydantic бол "яаж шалгах вэ" гэсэн асуултыг "юу байх ёстой вэ" гэсэн асуулт болгож хувиргадаг хэрэгсэл юм.
Төрийн байгууллагад очиж өргөдөл гаргаж байна гэж төсөөлье. Хоёр өөр систем байж болно.
Эхний систем: чөлөөт бичиг. Та цагаан цаасан дээр хүссэнээ бичээд өгнө. Ажилтан уншиж, юу дутууг олж, буцаана. "Овог бичээгүй байна." Та бичээд дахин өгнө. "Утасны дугаар нь буруу форматтай." Дахин бичнэ. "Төрсөн он ирээдүйд байна." Дахин. Гурван удаа явж ирлээ.
Хоёр дахь систем: маягт. Танд хэвлэсэн маягт өгнө. Талбар бүр нэртэй. Заавал бөглөх талбарууд одтой. Утасны дугаарын нүд нь найман нүдтэй, зөвхөн тоо орно. Төрсөн оны нүд нь дөрвөн оронтой.
Маягт бөглөж эхлэхэд л та юу шаардагдаж байгааг харна. Буруу бөглөвөл шалгалтын цонх нэг дор бүх алдааг хэлнэ: "Овог дутуу, утас буруу, он буруу." Нэг удаа засаад өгнө.
Pydantic model бол тэр маягт юм. Та түүнийг зарлахад:
Шаардлага ил тод болно (/docs дээр харагдана)
Шалгалт автоматаар болно
Алдаанууд нэг дор ирнэ
Маягт дахин ашиглагдана (олон endpoint дээр)
Одоо хамгийн чухал холбоо. Курс 2-ын Бүлэг 9-д та dataclass сурсан:
python
from dataclasses import dataclass
@dataclass
class Book:
title: str
author: str
year: int
is_available: bool = TrueОдоо Pydantic model-ыг харъя:
python
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
year: int
is_available: bool = TrueБараг ижилхэн. Import өөр. Decorator (@dataclass) байхгүй, оронд нь BaseModel-ээс өвлөж байна (Курс 2-ын Бүлэг 7-ын inheritance). Гэхдээ дотор нь — талбарын нэр, хоёр цэг, type hint, default утга — яг адилхан.
Курс 2-т би "энэ гурвал — dataclass + type hints + default утга — бол яг Pydantic-ийн хэлбэр" гэж хэлж байсан. Одоо та түүнийг өөрийн нүдээр харж байна. Тэр амлалт худал байгаагүй.
Тэгвэл ялгаа нь юу вэ
Хэрэв ижил харагдаж байгаа бол яагаад dataclass ашиглахгүй байна вэ?
Ялгаа нь ганцхан: dataclass шалгадаггүй, Pydantic шалгадаг.
Курс 2-ын Бүлэг 4-т сурсан үнэнийг санаарай: Python type hint-ийг албадан хэрэгжүүлдэггүй. Тэр бол зөвхөн шошго. Тиймээс энэ код ямар ч алдаагүй ажиллана:
python
from dataclasses import dataclass
@dataclass
class Book:
title: str
year: int
book = Book(title=42, year="маш эрт")
print(book)Гаралт:
Book(title=42, year='маш эрт')title нь str гэж зарласан атлаа тоо орсон. year нь int гэж зарласан атлаа текст орсон. Python юу ч хэлээгүй.
Одоо Pydantic-аар ижил зүйлийг оролдъё:
python
from pydantic import BaseModel
class Book(BaseModel):
title: str
year: int
book = Book(title=42, year="маш эрт")Гаралт:
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Book
title
Input should be a valid string [type=string_type, input_value=42, input_type=int]
year
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='маш эрт', input_type=str]Хоёр алдаа, нэг дор. Pydantic зогсоов.
Мессежийг сайтар хараарай — та түүнийг таньж байна уу? string_type, int_parsing, "Input should be a valid integer" — эдгээр нь яг Бүлэг 2-т үзсэн 422 хариуны дотор байсан үгс.
Учир нь тэр 422 хариу нь Pydantic-аас ирдэг. FastAPI validation-ыг өөрөө хийдэггүй; Pydantic хийдэг. Та Бүлэг 2-оос хойш Pydantic-тай ажиллаж ирсэн, зүгээр л мэдээгүй байсан.
Энэ зүйлийг тодорхой болгоё, учир нь энэ нь бүх зургийг цэгцэлнэ.
Бүлэг 2-т та ийм код бичсэн:
python
@app.get("/books/{book_id}")
def get_book(book_id: int):
.../books/abc руу хандахад 422 ирсэн. Тэр шалгалтыг хэн хийсэн бэ? Pydantic.
FastAPI таны type hint (book_id: int) -ыг уншиж, Pydantic руу дамжуулж, "энэ утга int мөн үү?" гэж асуусан. Pydantic үгүй гэж хариулж, дэлгэрэнгүй алдаа өгсөн. FastAPI түүнийг 422 хариу болгосон.
Query parameter дээр ч ижил. Bool хувиргалт (true/1/yes) — тэр ч бас Pydantic.
Тиймээс энэ бүлэгт бид шинэ зүйл сурч байгаа биш. Бид аль хэдийн ажиллаж байсан машиныг нээж, түүнийг өөрсдөө удирдаж эхэлж байна. Өмнө нь та ганц утга (book_id: int) шалгуулж байсан. Одоо та бүтэн объект шалгуулах болно.
Энэ асуултын хариу нь FastAPI гэдэг framework-ийн үндсэн санаа юм.
FastAPI-ийн зохиогч Sebastián Ramírez нэг зүйлийг анзаарсан: Python хөгжүүлэгчид аль хэдийн type hint бичдэг — кодоо уншимтгай болгох гэж, editor-оос тусламж авах гэж. Тэр мэдээлэл аль хэдийн кодонд байдаг.
Тэгвэл яагаад түүнийг ашиглахгүй байгаа юм бэ?
Бусад framework-ууд танаас шалгалтыг тусад нь бичихийг шаарддаг байсан: тусдаа schema файл, тусдаа validator class, тусдаа тохиргоо. Нэг зүйлийг хоёр удаа бичдэг — нэг удаа Python-д, нэг удаа шалгалтад. Хоёр нь салж, зөрчилддөг.
FastAPI өөр замыг сонгосон: type hint-ийг ганц эх сурвалж болгох. Та нэг удаа бичнэ, тэгээд:
Editor тань автоматаар гүйцээж өгнө
Pydantic түүгээр шалгалт хийнэ
FastAPI түүгээр 422 хариу үүсгэнэ
OpenAPI түүгээр баримт бичиг үүсгэнэ
/docs түүгээр маягт зурна
Нэг бичлэг, таван ашиг. Энэ бол FastAPI яагаад бусдаас өөр байдгийн шалтгаан юм.
Курс 2-ын Бүлэг 4-т би "type hint-ийг сурах нь чухал, учир нь орчин үеийн framework-ууд тэдгээр дээр баригдсан" гэж хэлж байсан. Одоо та тэр өгүүлбэрийн бүрэн утгыг харж байна.
Практик асуулт: Pydantic-ыг суулгах хэрэгтэй юу?
Үгүй. Та түүнийг аль хэдийн суулгасан. Бүлэг 1-д pip install "fastapi[standard]" гэж бичихэд Pydantic автоматаар суусан — FastAPI түүнгүйгээр ажиллаж чадахгүй тул заавал дагалддаг.
Батлахыг хүсвэл терминал дээр ((venv) идэвхтэй байхад):
pip show pydanticХувилбар болон байршил харагдана. Одоогийн тогтвортой хувилбар нь Pydantic v2 бөгөөд энэ сургалт бүхэлдээ түүн дээр бичигдсэн.
Энэ нь чухал, учир нь Pydantic v1 болон v2 хоёрын синтакс зарим газар өөр байдаг. Интернэтээс жишээ хайхад хуучин v1 кодтой тааралдаж болно. Хэрэв та ойлгомжгүй алдаа авбал — жишээ нь .dict() гэсэн method ажиллахгүй байвал — тэр нь v1 код байх магадлалтай. v2-т тэр .model_dump() болсон. Бид зөвхөн v2 хэрэглэнэ.
Энэ бүлэг болон дараагийн бүлгүүдэд та Pydantic-ийн дараах чадваруудыг сурна. Одоо зөвхөн жагсаалт болгон харна уу; тус бүр өөрийн хичээлтэй.
Төрөл шалгах. population: int — текст ирвэл татгалзана.
Заавал/заавал биш. Default утгатай талбар нь заавал биш; байхгүй бол заавал (Хичээл 4).
Хувиргах. "42" гэсэн текст int талбарт орвол Pydantic түүнийг 42 болгоно. Энэ бол уян хатан байдал, гэхдээ хязгаартай — "маш их" гэдгийг тоо болгож чадахгүй.
Гүн бүтэц. Model дотор model (Бүлэг 6). Хот дотор аймаг, аймаг дотор координат.
Хязгаарлалт. Хүн ам сөрөг байж болохгүй, нэр хоосон байж болохгүй, он 1000-2100 хооронд байх ёстой. Эдгээрийг зарлаж болно.
Нарийн шалгалт. Өөрийн дүрэм бичих (энэ сургалтын хүрээнээс гадуур, гэхдээ боломжтой гэдгийг мэдэж байх нь зүйтэй).
Бид эхний дөрвийг нь сурна. Үлдсэн нь таны цаашдын зам.
Хоёр газар, хоёр өөр зорилгоор. Энэ ялгааг эхнээс нь ойлгох нь чухал.
Оролт дээр (Бүлэг 5). Хэрэглэгч танд өгөгдөл илгээхэд Pydantic model нь хаалганы харуул болно. Буруу өгөгдөл дотогш орохгүй. Таны функц ажиллаж эхлэх үед өгөгдөл нь аль хэдийн зөв байна — та юу ч шалгах шаардлагагүй.
Гаралт дээр (Бүлэг 6). Та хэрэглэгч рүү өгөгдөл буцаахад Pydantic model нь гарцын шүүлтүүр болно. Зөвхөн зарласан талбарууд гарна; санамсаргүй илүү зүйл (жишээ нь нууц үг, дотоод тэмдэглэл) гадагш алдагдахгүй.
Оролтын харуул, гарцын шүүлтүүр. Нэг хэрэгсэл, хоёр үүрэг.
"Энэ нь код удаашруулахгүй юу?"
Шалгалт хийхэд цаг зарцуулагдах нь үнэн. Гэхдээ Pydantic v2-ын гол хэсэг нь Rust хэл дээр бичигдсэн бөгөөд маш хурдан. Практик дээр таны API-ийн хурдны хязгаарлагч нь validation биш, харин өгөгдлийн сан эсвэл сүлжээ байх болно.
Түүнчлэн — шалгалтгүй код бол хурдан биш, зүгээр л эвдрэхээ хойшлуулж байгаа юм.
"Би өөрөө шалгаж болохгүй гэж үү?"
Болно. Гэхдээ дээрх хорин таван мөрийг санаарай. Дараа нь тэр кодыг гурван endpoint дээр давтахыг санаарай. Дараа нь шинэ талбар нэмэх үед гурван газар засахыг санаарай.
Pydantic бол таны бичихээс зайлсхийж болох код юм.
"Dataclass-аа хэрэглэж болох уу?"
FastAPI dataclass-ыг ч дэмждэг. Гэхдээ Pydantic model илүү их зүйл хийдэг (шалгалт, хувиргалт, баримт бичиг) тул FastAPI-д зориулж бичихдээ Pydantic-ыг сонгоно.
Dataclass таны кодны дотоод хэсэгт хэрэгтэй хэвээр байна — вэбтэй холбоогүй объектуудад. Курс 2-т сурсан зүйл тань хэрэггүй болоогүй; зүгээр л одоо танд илүү хүчирхэг хэрэгсэл нэмэгдэж байна.
Гадаад ертөнцөөс ирсэн өгөгдлийг шалгах ёстой. Гар аргаар хийвэл олон арван if, давтагдмал, алдаатай.
Pydantic нь "яаж шалгах вэ" гэдгийг "юу байх ёстой вэ" болгож хувиргадаг — та зөвхөн зарлана, тэр шалгана.
Зүйрлэл: Pydantic model бол хатуу шаардлагатай маягт — талбар бүр нэртэй, төрөлтэй, заавал эсэх нь тодорхой.
Синтакс нь Курс 2-ын dataclass-тай бараг ижил. Ялгаа: dataclass шалгадаггүй, Pydantic шалгадаг.
Та аль хэдийн Pydantic ашиглаж байсан — Бүлэг 2-ын бүх 422 хариу түүнээс ирсэн.
FastAPI Pydantic дээр баригдсан: нэг type hint бичихэд шалгалт, алдааны хариу, баримт бичиг, /docs маягт бүгд үүснэ.
Pydantic аль хэдийн суусан (fastapi[standard]-тай хамт). Бид v2 ашиглана.
Хоёр үүрэг: оролтын харуул (Бүлэг 5), гарцын шүүлтүүр (Бүлэг 6).
Ойлголт тодорхой боллоо. Дараагийн хичээлд бид гараа ажиллуулна: анхны Pydantic model-оо бичиж, түүнээс объект үүсгэж, dataclass-тай зэрэгцүүлэн харьцуулж, Pydantic яг юу хийж байгааг өөрийн нүдээр харна. Тэнд бид BaseModel-ийн бүх үндсэн зан төлөвийг гар дээрээ мэдрэх болно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.