Ачааллж байна...
Өмнөх хичээлд таны бүх талбар заавал байсан. Хэрэглэгч дөрвүүлээ өгөх ёстой байсан; аль нэгийг нь орхивол missing алдаа гарч байсан.
Гэхдээ бодит амьдрал ийм биш. Ном нэмэхэд гарчиг, зохиолч заавал хэрэгтэй — гэхдээ тайлбар байж ч болно, байхгүй ч болно. Үнэлгээ хараахан өгөгдөөгүй байж болно. Хэл нь ихэвчлэн монгол тул түүнийг заавал асуух шаардлагагүй, зүгээр л "монгол" гэж үзэж болно.
Энэ хичээлд бид заавал бус талбар үүсгэж сурна. Хоёр өөр хэрэгсэл байна: default утга ба Optional (None байж болох). Тэдгээрийн ялгааг ойлгох нь чухал, учир нь тэд өөр өөр зүйл илэрхийлдэг. Курс 2-ын Бүлэг 4-ийн None болон Бүлэг 3-ын default утгын мэдлэг энд шууд ажиллана.
Курс 2-ын Бүлэг 3-т та функцийн default утгыг сурсан. Курс 2-ын Бүлэг 9-т dataclass-ын default утгыг сурсан. Pydantic-д яг ижил:
test_model.py файлд (эсвэл шинэ туршилтын файлд) бичнэ:
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
language: str = "монгол"
is_available: bool = True
book = Book(title="Цог хийморь", author="Ч. Лодойдамба")
print(book)Ажиллуулна:
python test_model.pyГаралт:
title='Цог хийморь' author='Ч. Лодойдамба' language='монгол' is_available=TrueЮу болов
Хоёр талбар (title, author) заавал — default утгагүй. Хоёр талбар (language, is_available) default утгатай — тус тус "монгол" ба True.
Book үүсгэхэд бид зөвхөн title болон author өгсөн. Гэхдээ language нь "монгол", is_available нь True болсон. Хэрэглэгч өгөөгүй тул Pydantic default утгыг ашигласан.
Дүрэм — Курс 2-оос танил: default утгатай талбар заавал бус; default утгагүй талбар заавал. Энэ бол Python-ы функцийн ердийн дүрэм, Pydantic зүгээр л түүнийг өвлөсөн.
Default утгыг дарж бичих
Мэдээж хэрэглэгч default утгыг өөрчилж болно:
python
book = Book(
title="War and Peace",
author="Л. Толстой",
language="орос",
)
print(book)Гаралт:
title='War and Peace' author='Л. Толстой' language='орос' is_available=Truelanguage нь "орос" болсон — хэрэглэгч өгсөн тул default дарагдсан. is_available нь өгөгдөөгүй тул True хэвээр.
Одоо өөр төрлийн заавал бус талбар руу орно. Заримдаа талбар нь утгагүй байж болох ёстой. Жишээ нь номын тайлбар: бичсэн бол текст, бичээгүй бол... юу?
Курс 2-ын Бүлэг 4-т та None болон Optional-ыг сурсан. None бол "утга байхгүй" гэсэн тусгай утга. Талбар нь текст эсвэл None байж болно гэдгийг ингэж зарлана:
python
# test_model.py
from pydantic import BaseModel
class Book(BaseModel):
title: str
author: str
description: str | None = None
book1 = Book(title="Цог хийморь", author="Ч. Лодойдамба")
print(book1)
book2 = Book(
title="Цагаан хэрэм",
author="С. Эрдэнэ",
description="Монголын сонгодог роман",
)
print(book2)Гаралт:
title='Цог хийморь' author='Ч. Лодойдамба' description=None
title='Цагаан хэрэм' author='С. Эрдэнэ' description='Монголын сонгодог роман'str | None гэж юу вэ
description: str | None = None гэсэн мөрийг задалъя. Гурван хэсэгтэй.
description — талбарын нэр.
str | None — type hint. Босоо зураас (|) нь "эсвэл" гэсэн утгатай. Курс 2-ын Бүлэг 4-т та үүнийг сурсан: str | None гэдэг нь "текст эсвэл None" гэсэн үг. Өөрөөр хэлбэл энэ талбар текст байж болно, эсвэл огт утгагүй байж болно.
= None — default утга. Хэрэглэгч тайлбар өгөхгүй бол None гэж үзнэ.
Тиймээс book1-д тайлбар өгөөгүй тул description нь None. book2-д өгсөн тул текст.
Хуучин Optional бичлэг
Интернэтээс ийм бичлэг харж магадгүй:
python
from typing import Optional
description: Optional[str] = NoneOptional[str] нь str | None-тэй яг ижил утгатай. Энэ бол хуучин бичлэг — Курс 2-т дурдсанчлан. Орчин үеийн Python-д str | None илүү товч, ойлгомжтой тул бид түүнийг ашиглана. Гэхдээ Optional[str] харвал энэ нь ижил зүйл гэдгийг мэдэж байгаарай.
Нэг чухал зүйлийг тодруулъя, учир нь энэ нь эхэндээ будлиантай.
description: str | None = None гэсэн мөрөнд хоёр зүйл байна:
str | None — талбар нь текст эсвэл None байж болно (төрлийн зарлал).
= None — хэрэглэгч өгөөгүй бол утга нь None (default утга).
Эдгээр нь салангид зүйл боловч ихэвчлэн хамт явдаг. Яагаад? Учир нь хэрэв талбар None байж болох бол default утгыг нь None болгох нь хамгийн байгалийн сонголт юм.
Гэхдээ заавал биш. Дараах хувилбаруудыг харьцуулъя.
Энэ хэсэг чухал. Дөрвөн өөр талбарын зарлалыг харж, тус бүр юу гэсэн үг болохыг ойлгоё.
python
class Book(BaseModel):
a: str # 1. Заавал текст
b: str = "монгол" # 2. Заавал бус, default текст
c: str | None # 3. Заавал, гэхдээ None байж болно
d: str | None = None # 4. Заавал бус, default NoneНэг нэгээр нь.
1. a: str — Заавал. Хэрэглэгч текст өгөх ёстой. Өгөхгүй бол missing алдаа. None өгч болохгүй.
2. b: str = "монгол" — Заавал бус. Өгөхгүй бол "монгол". Гэхдээ өгвөл заавал текст байх ёстой — None өгч болохгүй.
3. c: str | None — Энэ бол хамгийн будлиантай нь. Талбар заавал (default байхгүй), гэхдээ утга нь текст эсвэл None байж болно. Өөрөөр хэлбэл хэрэглэгч ямар нэг зүйл өгөх ёстой — гэхдээ тэр зүйл нь null байж болно. "Заавал өг, гэхдээ null өгч болно" гэсэн хачирхалтай хослол. Практикт ховор хэрэглэгддэг.
4. d: str | None = None — Заавал бус. Өгөхгүй бол None. Өгвөл текст эсвэл None. Хамгийн түгээмэл, хамгийн ашигтай хэлбэр.
Ихэнх тохиолдолд танд 2 эсвэл 4 хэрэгтэй байна.
Заавал бус, боломжийн default утгатай (хэл, төлөв, тоо) -> 2-р хэлбэр: b: str = "монгол".
Заавал бус, "утга байхгүй" гэсэн ойлголттой (тайлбар, зураг, огноо) -> 4-р хэлбэр: d: str | None = None.
Дөрвөн хувилбарыг гар дээрээ мэдрэе:
python
# test_model.py
from pydantic import BaseModel
class Demo(BaseModel):
a: str
b: str = "монгол"
c: str | None
d: str | None = None
# c-г заавал өгөх ёстой (None ч болно), a-г заавал өгөх ёстой
demo = Demo(a="текст", c=None)
print(demo)Гаралт:
a='текст' b='монгол' c=None d=Nonea өгсөн. c-д None өгсөн (заавал тул өгөх ёстой). b болон d өгөөгүй тул default ("монгол" ба None).
Одоо c-г орхиж үзье:
python
demo = Demo(a="текст")Гаралт:
pydantic_core._pydantic_core.ValidationError: 1 validation error for Demo
c
Field required [type=missing, input_value={'a': 'текст'}, input_type=dict]c дутуу — missing алдаа. Учир нь c: str | None нь заавал (default байхгүй). None байж болно ч, өгөх ёстой.
Энэ туршилт нь 3-р хэлбэрийн хачирхалтай байдлыг тодорхой харуулна. Тиймээс практикт та бараг үргэлж = None нэмж, 4-р хэлбэр болгодог.
Одоо энэ мэдлэгээ endpoint-д авчирна. main.py файлаа дараах кодоор солино:
python
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="Номын API")
class Book(BaseModel):
title: str
author: str
year: int
language: str = "монгол"
description: str | None = None
is_available: bool = True
@app.post("/books")
def create_book(book: Book):
return bookХадгална.
Хамгийн бага өгөгдлөөр туршина
/docs дээр POST /books -> Try it out. JSON-ыг дараахаар солино — зөвхөн заавал талбаруудыг:
json
{
"title": "Цог хийморь",
"author": "Ч. Лодойдамба",
"year": 1962
}Execute дарна.
Server response (статус 200):
json
{
"title": "Цог хийморь",
"author": "Ч. Лодойдамба",
"year": 1962,
"language": "монгол",
"description": null,
"is_available": true
}Гурван талбар л илгээсэн. Гэхдээ хариунд зургаа байна. Pydantic дутуу гурвыг default утгаар нөхсөн: language нь "монгол", description нь null, is_available нь true.
Энэ бол хэрэглэгчид тав тухтай. Тэд зөвхөн шаардлагатай зүйлээ өгнө; үлдсэнийг таны API боломжийн утгаар нөхнө.
Бүх талбараар туршина
json
{
"title": "War and Peace",
"author": "Л. Толстой",
"year": 1869,
"language": "орос",
"description": "Дэлхийн сонгодог",
"is_available": false
}Server response (статус 200):
json
{
"title": "War and Peace",
"author": "Л. Толстой",
"year": 1869,
"language": "орос",
"description": "Дэлхийн сонгодог",
"is_available": false
}Бүх утга хэрэглэгчийнхээр солигдсон. Default-ууд дарагдсан.
Энэ бол чухал — /docs заавал ба заавал бус талбарыг ялгаж харуулна.
/docs дээр POST /books мөрийг задалж, Request body доорх Schema хэсгийг хараарай (эсвэл "Schema" таб дээр товшино). Ойролцоогоор ийм харагдана:
title * string
author * string
year * integer
language string default: монгол
description string | null default: null
is_available boolean default: trueОд (*) бүхий талбарууд заавал — title, author, year. Од байхгүй талбарууд заавал бус — тэдгээр нь default утгатай, /docs түүнийг харуулж байна.
Мөн жишээ JSON (Try it out дээр гарч ирдэг) нь ихэвчлэн заавал талбаруудыг онцолж, заавал бусыг нь default утгаар нь харуулна. Хэрэглэгч аль талбарыг заавал өгөх ёстойг баримт бичгээс шууд харна.
Дахин хэлэхэд: та энэ баримт бичгийг бичээгүй. = "монгол", | None = None гэсэн жижиг зарлалуудаас FastAPI бүгдийг ойлгосон.
Одоохондоо create_book зүгээр л буцааж байна ("echo"). Бодит байдал дээр бид түүнийг хадгалах ёстой. Бид Бүлэг 5-д үүнийг зөв хийнэ, гэхдээ Optional талбар яагаад ашигтайг харуулах жишээ энд бий:
python
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="Номын API")
books = []
next_id = 1
class Book(BaseModel):
title: str
author: str
year: int
language: str = "монгол"
description: str | None = None
@app.post("/books", status_code=201)
def create_book(book: Book):
global next_id
saved = book.model_dump()
saved["id"] = next_id
books.append(saved)
next_id += 1
return saved
@app.get("/books")
def get_books():
return booksХадгална.
Кодын задаргаа
books = [] — хоосон жагсаалт, шинэ номуудыг хадгална. next_id = 1 — дараагийн ном ямар дугаартай байхыг хянана.
book.model_dump() — өмнөх хичээлээс танил. Pydantic model-ыг Python dictionary болгож байна. Яагаад? Учир нь бид түүнд id талбар нэмэх гэж байгаа, model нь id талбаргүй. Dictionary болгосны дараа шинэ түлхүүр нэмэхэд хялбар.
saved["id"] = next_id — dictionary-д id нэмлээ.
global next_id — Курс 2-ын Бүлэг 3-аас. Функцийн гаднах next_id хувьсагчийг өөрчлөх гэж байгаа тул global зарлах ёстой. (Энэ бол түр зуурын шийдэл — Түвшин 4-т өгөгдлийн сан id-г өөрөө үүсгэнэ, global хэрэггүй болно.)
Туршина
/docs дээр дараах хоёр номыг дараалан илгээнэ:
Эхнийх (бүрэн):
json
{
"title": "Цог хийморь",
"author": "Ч. Лодойдамба",
"year": 1962,
"description": "Сонгодог роман"
}Хоёр дахь (хамгийн бага):
json
{
"title": "Цагаан хэрэм",
"author": "С. Эрдэнэ",
"year": 1971
}Дараа нь GET /books:
Server response:
json
[
{"title":"Цог хийморь","author":"Ч. Лодойдамба","year":1962,"language":"монгол","description":"Сонгодог роман","id":1},
{"title":"Цагаан хэрэм","author":"С. Эрдэнэ","year":1971,"language":"монгол","description":null,"id":2}
]Хоёр номын ялгааг анзаараарай. Эхнийхэд description нь текст, хоёр дахьд null. Хоёуланд нь language нь "монгол" (default). Хоёуланд нь id нэмэгдсэн.
null талбар нь ашигтай: хэрэглэгч "энэ номд тайлбар байхгүй" гэдгийг тодорхой харна. Хэрэв description талбар огт байхгүй байсан бол хэрэглэгч эргэлзэх байсан — "тайлбар байхгүй юу, эсвэл алдаа гарсан уу?". null нь "тодорхой байхгүй" гэсэн тодорхой хариу юм.
Заавал талбарыг заавал бусын дараа тавих (dataclass дээр)
Курс 2-ын Бүлэг 9-т dataclass дээр энэ дүрэм байсан: заавал талбар default-тай талбарын өмнө байх ёстой. Pydantic дээр энэ дүрэм байхгүй — Pydantic талбарыг нэрээр нь ялгадаг тул дараалал чөлөөтэй:
python
class Book(BaseModel):
language: str = "монгол" # default-тай
title: str # заавал — dataclass бол энд алдаа өгөх байсанPydantic дээр энэ ажиллана. Гэхдээ уншихад заавал талбаруудыг эхэнд тавих нь илүү цэгцтэй тул зуршил болгон тэгэх нь зүйтэй.
None-ыг зарлалгүй өгөх
python
class Book(BaseModel):
description: str # str, None биш
book = Book(title="...", author="...", year=1962, description=None)Гаралт:
pydantic_core._pydantic_core.ValidationError: 1 validation error for Book
description
Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]description: str нь "заавал текст" гэсэн үг — None зөвшөөрөгдөхгүй. None өгөхийг хүсвэл str | None гэж зарлах ёстой.
Хувирдаг default (mutable default) — жижиг занга
Курс 2-ын Бүлэг 3-т та функцийн default-д хоосон жагсаалт ([]) ашиглах аюулыг сурсан байж магадгүй. Pydantic-д жагсаалт эсвэл dictionary-г default болгохдоо тусгай бичлэг хэрэгтэй:
python
from pydantic import BaseModel, Field
class Book(BaseModel):
title: str
tags: list[str] = Field(default_factory=list)tags: list[str] = [] гэж шууд бичих нь Pydantic v2-т үнэндээ ажилладаг (Pydantic хамгаалалт хийдэг), гэхдээ Field(default_factory=list) нь илүү тодорхой, найдвартай хэлбэр юм. Field гэдэг хэрэгслийг бид дэлгэрэнгүй судлахгүй, гэхдээ жагсаалт/dictionary default хэрэгтэй бол энэ бичлэгийг ашиглана гэдгийг мэдэж байгаарай. Энгийн default (текст, тоо, bool, None) шууд бичигдэнэ.
Хүсвэл Book model-д rating: float | None = None гэсэн талбар нэмээд, зарим номд үнэлгээ өгч, заримд нь өгөлгүй туршаад үзээрэй. null болон тоон утга хэрхэн зэрэгцэн оршихыг ажиглаарай.
Сонирхвол дээрх дөрвөн хувилбарын (a, b, c, d) model-ыг /docs дээр туршиж, аль нь од (*) тэмдэгтэй, аль нь тэмдэггүй болохыг харна уу. Заавал ба заавал бусын ялгаа баримт бичигт хэрхэн тусгагдахыг өөрийн нүдээр харах нь ойлголтыг бататгана.
Default утга (language: str = "монгол") — талбарыг заавал бус болгоно; хэрэглэгч өгөөгүй бол default хэрэгжинэ.
str | None — талбар текст эсвэл None байж болно (Курс 2-ын Бүлэг 4). Хуучин бичлэг: Optional[str].
str | None = None — хамгийн түгээмэл заавал бус хэлбэр: өгөхгүй бол None.
Дөрвөн хувилбарыг ялга: заавал текст / default текст / заавал(None болно) / заавал бус(default None).
Ихэвчлэн танд хэрэгтэй нь: боломжийн default-той бол = утга, "утга байхгүй" ойлголттой бол | None = None.
/docs заавал талбарыг од (*)-оор, заавал бусыг default утгатайгаар харуулна.
Pydantic-д талбарын дараалал чөлөөтэй (dataclass-аас ялгаатай), гэхдээ заавлыг эхэнд бичих нь цэгцтэй.
Жагсаалт/dictionary default-д Field(default_factory=list) ашиглана.
Бүлэг 4 дууслаа. Та одоо Pydantic model бичиж, объект хүлээж авч, автомат validation авч, заавал ба заавал бус талбарыг зөв зарлаж чадна. Таны API-ийн хамгаалалтын хана босч дууслаа.
Гэхдээ бид одоог хүртэл зөвхөн @app.post гэсэн method-ыг бүрхэг ашиглаж, түүнийг тайлбарлаагүй өнгөрсөн. Яагаад POST? GET-ээс юугаараа ялгаатай? Хэзээ алийг нь ашиглах вэ? Дараагийн бүлэг бүхэлдээ HTTP method-ийн утга санаанд зориулагдана. Бид POST-ыг зөв ойлгож, дараа нь PUT (засах), DELETE (устгах)-ыг нэмж, эцэст нь Түвшин 2-ын гол бүтээн байгуулалт болох Тэмдэглэлийн API v1 руу ойртоно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.