Ачааллж байна...
Өмнөх хичээлд бид Pydantic яагаад оршдог, ямар асуудлыг шийддэгийг ойлгосон. Одоо гараа ажиллуулна. Энэ хичээлд бид анхны Pydantic model-оо бичиж, түүнээс объект үүсгэж, талбаруудад нь хандаж, dataclass-тай хажуу хажууд нь тавьж харьцуулна.
Энэ бол дадлагын хичээл. Бид FastAPI-гүйгээр, зөвхөн Pydantic-тай ажиллана — model-ыг тусад нь, энгийн Python скриптээр туршина. Ингэснээр model өөрөө яг юу хийдгийг вэб орчны нэмэлт давхаргагүйгээр цэвэрхэн харна. Дараагийн хичээлүүдэд бид түүнийг FastAPI-д залгана.
Энэ хичээлд main.py-г бус, тусдаа туршилтын файл ашиглана. Төслийн хавтастаа test_model.py гэсэн файл үүсгэнэ.
Энэ файлыг бид fastapi dev-ээр биш, энгийн Python-оор ажиллуулна. Тиймээс хоёр дахь терминал нээх нь тохиромжтой (VS Code-ийн терминал хэсэгт + товч). Нэг терминалд сервер ажиллаж байх шаардлагагүй — энэ файл серверээс хамааралгүй.
Ажиллуулах тушаал ((venv) идэвхтэй байхад):
python test_model.pytest_model.py файлд бичнэ:
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
year: int
pages: intАжиллуулна:
python test_model.pyЮу ч гарахгүй. Энэ бол зөв — бид зөвхөн model зарласан, түүнийг ашиглаагүй. Class зарлах нь юу ч хийхгүй; түүнээс объект үүсгэх хүртэл юу ч болохгүй.
Кодын задаргаа
from pydantic import BaseModel — Pydantic-аас BaseModel гэдэг class-ыг авч байна.
class Book(BaseModel): — Book гэдэг шинэ class үүсгэж, BaseModel-ээс өвлөж байна. Курс 2-ын Бүлэг 7-ын inheritance: хаалт доторх нэр бол эцэг class. Book нь BaseModel-ийн бүх чадварыг өвлөнө — шалгалт, хувиргалт, JSON руу гарах чадвар.
Дотор нь дөрвөн талбар. Тус бүр нэр, хоёр цэг, type hint гэсэн хэлбэртэй. Утга оноогоогүй, зөвхөн зарласан. Энэ нь "энэ model-д ийм талбарууд байх ёстой" гэсэн үг.
Одоо model-оо ашиглая. Файлаа дараах кодоор солино:
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
year: int
pages: int
book = Book(
title="Цог хийморь",
author="Ч. Лодойдамба",
year=1962,
pages=560,
)
print(book)Ажиллуулна.
Гаралт:
title='Цог хийморь' author='Ч. Лодойдамба' year=1962 pages=560Юу болов
Book(...) — model-оос объект үүсгэлээ. Курс 2-ын Бүлэг 9-т dataclass-аас объект үүсгэж байсантай яг адил. Талбар бүрт нэрээр нь утга өглөө: title="...", year=1962.
print(book) — Pydantic объект нь өөрийгөө цэвэрхэн харуулж байна: талбар бүр нэр, утгатайгаа. Курс 2-ын Бүлэг 8-т сурсан __str__/__repr__-ыг санаж байна уу? Pydantic түүнийг таны өмнөөс хийж өгсөн — та __repr__ бичээгүй ч цэвэрхэн харагдаж байна.
Объектын талбарууд руу цэгээр хандана — dataclass-тай яг адил:
python
# test_model.py (print хэсгийг солино)
print(book.title)
print(book.year)
print(book.pages)
print(f"{book.title} ном {book.year} онд хэвлэгдсэн")Гаралт:
Цог хийморь
1962
1962 онд хэвлэгдсэн ...сүүлийн мөр бүрэн:
Цог хийморь ном 1962 онд хэвлэгдсэнbook.title, book.year — цэгээр хандаж талбарын утгыг авлаа. Энэ бол Курс 2-ын класс болон dataclass-аас танил. Pydantic model нь ердийн Python объект шиг ажилладаг — цэгээр хандах, f-string-д оруулах, бүгд адилхан.
Энэ бол хичээлийн гол хэсэг. Model-ыг санаатайгаар эвдэж, юу болохыг харъя.
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
year: int
pages: int
book = Book(
title="Цог хийморь",
author="Ч. Лодойдамба",
year="маш эрт",
pages=560,
)
print(book)year талбарт тоо биш, "маш эрт" гэсэн текст өглөө.
Ажиллуулна.
Гаралт:
Traceback (most recent call last):
File "test_model.py", line 11, in <module>
book = Book(
pydantic_core._pydantic_core.ValidationError: 1 validation error for Book
year
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='маш эрт', input_type=str]
For further information visit https://errors.pydantic.dev/2.x/v/int_parsingBook объект огт үүсээгүй. Pydantic зогсоов.
Мессежийг задалж уншъя. 1 validation error for Book — Book model-д нэг алдаа. year — аль талбар дээр. Input should be a valid integer — юу байх ёстой. unable to parse string as an integer — яагаад болоогүй. type=int_parsing — алдааны төрөл. input_value='маш эрт' — юу ирсэн.
Эдгээр үг танил байх ёстой. Бүлэг 2-ын 422 хариу дотор яг эдгээр байсан. Учир нь тэр 422 нь яг энэ ValidationError-оос үүсдэг. FastAPI энэ алдааг барьж аваад JSON болгодог.
Хоёр талбар эвдэж үзье:
python
# test_model.py (Book(...) хэсгийг солино)
book = Book(
title=42,
author="Ч. Лодойдамба",
year="маш эрт",
pages=560,
)title-д тоо (текст байх ёстой), 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]2 validation errors — хоёр алдаа, нэг дор. Pydantic эхний алдаан дээр зогсоогүй; бүх талбарыг шалгаж, олсон бүх алдаагаа мэдээлсэн.
Өмнөх хичээлд ярьсан гар аргын кодыг санаж байна уу? Тэр эхний алдаан дээр зогсдог байсан. Pydantic илүү сайн: хэрэглэгч бүх алдаагаа нэг удаад хараад, нэг удаад засна.
python
# test_model.py (Book(...) хэсгийг солино)
book = Book(
title="Цог хийморь",
year=1962,
)author болон pages дутуу.
Гаралт:
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Book
author
Field required [type=missing, input_value={'title': 'Цог хийморь', 'year': 1962}, input_type=dict]
pages
Field required [type=missing, input_value={'title': 'Цог хийморь', 'year': 1962}, input_type=dict]Шинэ алдааны төрөл: missing. Мессеж нь Field required — "энэ талбар заавал". Бүлэг 2-т query parameter дутуу байхад яг ийм missing алдаа гарч байсныг санаж байна уу? Ижил механизм.
Тиймээс дүрэм: default утга өгөөгүй бүх талбар заавал байх ёстой. Дараагийн хичээлүүдэд бид default утга нэмж, талбарыг заавал бус болгож сурна.
Одоо сонирхолтой зан төлөв. Дараах кодыг ажиллуулна:
python
# test_model.py (Book(...) хэсгийг солино)
book = Book(
title="Цог хийморь",
author="Ч. Лодойдамба",
year="1962",
pages="560",
)
print(book)
print(type(book.year))year болон pages-т текст өгсөн ("1962", "560") — тоо биш.
Гаралт:
title='Цог хийморь' author='Ч. Лодойдамба' year=1962 pages=560
<class 'int'>Алдаа гараагүй. Түүнээс ч илүү — book.year нь одоо 1962, тоо (хашилтгүй), текст биш. type(book.year) нь <class 'int'> гэж баталж байна.
Юу болов? Pydantic "1962" гэсэн текстийг харж, "энэ талбар int байх ёстой, энэ текстийг int болгож чадах уу?" гэж бодсон. "1962" бол цэвэр тоон текст тул чадсан. Хувиргаад оруулсан.
Энэ бол уян хатан байдал. Яагаад ашигтай вэ? Учир нь вэбээс ирсэн бүх зүйл текст байдаг. Бүлэг 2-т та үүнийг харсан: хаягны 2 нь үнэндээ "2" байсан. Pydantic түүнийг автоматаар тоо болгосон тул та санаа зовох шаардлагагүй байсан.
Гэхдээ хязгаартай
Хувиргалт боломжтой үед л болно:
python
book = Book(
title="Цог хийморь",
author="Ч. Лодойдамба",
year="1962 он", # цэвэр тоо биш
pages=560,
)Гаралт:
pydantic_core._pydantic_core.ValidationError: 1 validation error for Book
year
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='1962 он', input_type=str]"1962" хувирсан, гэхдээ "1962 он" хувирахгүй — учир нь тэнд тоо биш үг холилдсон. Pydantic зөвхөн бүхэлдээ тоон текстийг хувиргадаг. Ямар нэг эргэлзээтэй бол татгалздаг.
Энэ бол зөв зан төлөв: уян хатан, гэхдээ болгоомжтой. Тодорхой хувиргалтыг хийдэг, эргэлзээтэйг татгалздаг.
Одоо хоёрыг зэрэгцүүлж, ялгааг гар дээрээ мэдрэе. Дараах кодыг ажиллуулна:
python
# test_model.py
from dataclasses import dataclass
from pydantic import BaseModel
@dataclass
class BookDataclass:
title: str
year: int
class BookPydantic(BaseModel):
title: str
year: int
# dataclass — буруу төрөл өгье
d = BookDataclass(title=42, year="маш эрт")
print("Dataclass:", d)
# Pydantic — ижил буруу төрөл өгье
try:
p = BookPydantic(title=42, year="маш эрт")
print("Pydantic:", p)
except Exception as e:
print("Pydantic алдаа өгсөн")Гаралт:
Dataclass: BookDataclass(title=42, year='маш эрт')
Pydantic алдаа өгсөнХоёр class бараг ижил кодтой. Ижил буруу өгөгдөл өглөө. Гэхдээ:
Dataclass дуугүй хүлээж авсан. title=42 (текст байх ёстой атлаа тоо), year="маш эрт" (тоо байх ёстой атлаа текст) — юу ч хэлээгүй. Курс 2-ын Бүлэг 4-ын үнэн: Python type hint-ийг албадан хэрэгжүүлдэггүй.
Pydantic зогсоов. Ижил өгөгдөл, өөр хариу. Учир нь Pydantic type hint-ийг шалгалт болгодог.
Энэ бол хоёрын цорын ганц боловч шийдвэрлэх ялгаа. Dataclass бол зөв кодод зориулсан цэвэр контейнер. Pydantic бол итгэж болохгүй өгөгдөлд зориулсан харуул. Гадаад ертөнцтэй харьцах бүх газар — API-ийн оролт — Pydantic хэрэгтэй.
try/except энд ашигласныг анзаараарай — Курс 1-ээс танил. Хэрэв try хэрэглэхгүй бол Pydantic-ийн алдаа программыг зогсоох байсан. FastAPI дотор энэ try/except-ыг FastAPI өөрөө хийж, алдааг 422 болгодог — та гараар барих шаардлагагүй.
Pydantic model нь JSON-той нягт холбоотой. Хоёр чухал method байна:
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
year: int
book = Book(title="Цог хийморь", author="Ч. Лодойдамба", year=1962)
# 1. Python dictionary болгох
print(book.model_dump())
# 2. JSON текст болгох
print(book.model_dump_json())Гаралт:
{'title': 'Цог хийморь', 'author': 'Ч. Лодойдамба', 'year': 1962}
{"title":"Цог хийморь","author":"Ч. Лодойдамба","year":1962}model_dump() — model-ыг Python dictionary болгоно. Гаралт нь ганц хашилттай (Python-ы dictionary).
model_dump_json() — model-ыг JSON текст болгоно. Гаралт нь давхар хашилттай (JSON стандарт).
Эдгээр нэр яагаад чухал вэ? Учир нь Pydantic v1-т эдгээр өөр нэртэй байсан: .dict() болон .json(). Хэрэв та интернэтээс .dict() гэсэн код харвал тэр нь хуучин v1 код. v2-т .model_dump(). Өмнөх хичээлд дурдсан ялгаа энэ.
FastAPI дотор та эдгээрийг ихэвчлэн гараар дуудахгүй — FastAPI model-ыг автоматаар JSON болгодог (Бүлэг 3-ын Хичээл 1-т сурсан хувиргалт нь Pydantic model дээр ч ажиллана). Гэхдээ өгөгдлийг өгөгдлийн санд хадгалахын өмнө dictionary болгох гэх мэт тохиолдолд model_dump() хэрэгтэй болно. Түвшин 4-т үүнийг харна.
Энэ хичээлийн test_model.py бол зөвхөн сургалтын зорилготой. Түүнийг устгаж болно, эсвэл дараа туршихад үлдээж болно — таны төслийн жинхэнэ кодтой (main.py) холбоогүй.
Дараагийн хичээлээс эхлэн бид Pydantic model-ыг main.py дотор, FastAPI-тай хамт ашиглана.
model_dump биш dict дуудах
python
book.dict()Гаралт:
PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead.Эсвэл хувилбараас хамааран алдаа өгч болно. Энэ бол v1 кодыг v2 дээр ажиллуулж байгаагийн шинж. Засвар: .model_dump().
Талбарын нэр буруу бичих
python
book = Book(titel="Цог хийморь", author="Ч. Лодойдамба", year=1962)title биш titel (үсэг андуурсан).
Гаралт:
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Book
title
Field required [type=missing, ...]
titel
Extra inputs are not permitted [type=extra_forbidden, ...]Хоёр алдаа. title дутуу (учир нь та түүнийг өгөөгүй). titel илүү (учир нь model-д тийм талбар байхгүй). Pydantic default байдлаар илүү талбарыг татгалздаг — энэ нь үсгийн алдааг барихад тустай.
BaseModel-ээс өвлөхгүй
python
class Book: # (BaseModel) байхгүй
title: str
year: int
book = Book(title="Цог хийморь", year=1962)Гаралт:
TypeError: Book() takes no arguments(BaseModel) байхгүй тул энэ бол ердийн Python class — Pydantic-ийн чадваргүй. Ердийн class-т __init__ гараар бичихгүй бол ийм байдлаар үүсгэж болохгүй. Засвар: class Book(BaseModel):.
Хүсвэл өөрийн model зохиож үзээрэй — жишээ нь Movie (title, director, year, duration) эсвэл Student (name, age, grade). Талбар нэмж, буруу утга өгч, алдааны мессеж уншаарай.
Сонирхвол хувиргалтын хязгаарыг судалж үзээрэй. year=3.14 (бутархай) гэж өгвөл юу болох вэ? year=True гэж өгвөл? pages="0x10" гэж өгвөл? Pydantic юуг хувиргаж, юуг татгалзахыг гар дээрээ мэдрэх нь ойлголтыг гүнзгийрүүлнэ.
Pydantic model нь BaseModel-ээс өвлөнө: class Book(BaseModel):.
Талбар бүр нэр : type hint хэлбэртэй; синтакс dataclass-тай бараг ижил.
Объект үүсгэх, талбарт цэгээр хандах — dataclass-тай адил.
Буруу төрөл өгвөл ValidationError гарч, объект үүсэхгүй. Олон алдаа нэг дор ирнэ.
Default утгагүй талбар заавал — дутуу бол missing алдаа.
Pydantic боломжтой хувиргалтыг хийдэг ("1962" -> 1962), эргэлзээтэйг татгалздаг ("1962 он").
Dataclass шалгадаггүй, Pydantic шалгадаг — цорын ганц боловч шийдвэрлэх ялгаа.
JSON руу: model_dump() (dictionary), model_dump_json() (JSON текст). v1-ийн .dict()/.json() биш.
Одоо та Pydantic model бичиж, түүний зан төлөвийг мэднэ. Гэхдээ бид түүнийг тусад нь, туршилтын файлд ажиллуулсан. Дараагийн хичээлд бид түүнийг FastAPI-тай холбоно: буруу өгөгдөл илгээхэд яг тэр ValidationError нь хэрхэн 422 JSON хариу болж хувирдгийг мөр мөрөөр нь харна. Тэр хариуг эхнээс нь дуустал уншина — энэ бол энэ бүлгийн онцлох мөч бөгөөд таны API-ийн хамгаалалтын зүрх юм.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.