Ачааллж байна...
Түвшин 2-ын төгсгөлд бид Тэмдэглэлийн API v1 бүтээсэн: нэг файл, далан мөр, бүрэн CRUD. Тэр ажиллаж байсан — гэхдээ хамгаалалтгүй, тохиргоогүй, өсөх бэлтгэлгүй.
Энэ хичээлд бид түүнийг v2 болгоно. Кодыг олон файлт мэргэжлийн бүтэц рүү шилжүүлж, API key-ээр хамгаалж, тохиргоог .env-ээс уншиж, алдааны хариуг нэгтгэнэ.
Хамгийн чухал зүйлийг эхлээд хэлье: зан төлөв нь бараг ижил хэвээр үлдэнэ. Ижил endpoint, ижил CRUD, ижил хариу. Гол ялгаа нь бүтэц болон хамгаалалт. Энэ бол Түвшин 3-ын гол сургамж: ижил ажлыг мэргэжлийн хэлбэрээр хийх.
Бодит ажилд энэ төрлийн ажлыг refactoring гэж нэрлэдэг — зан төлөвийг өөрчлөхгүйгээр кодын бүтцийг сайжруулах. Энэ бол хөгжүүлэгчийн өдөр тутмын ажлын том хэсэг юм.
v1 (Түвшин 2) | v2 (Түвшин 3) | |
|---|---|---|
Файл | 1 ( | 8 файл, 2 хавтас |
Router | Байхгүй ( |
|
Хамгаалалт | Байхгүй | API key (бичих үйлдэлд) |
Тохиргоо | Кодонд |
|
Алдаа | FastAPI-ийн стандарт | Нэгтгэсэн бүтэц |
Хуудаслалт | Байхгүй | Depends-ээр |
Хадгалалт | Санах ойд | Санах ойд (v3 засна) |
Сүүлийн мөрийг анзаараарай: хадгалалт өөрчлөгдөхгүй. v2 нь бүтцийн тухай, хадгалалтын тухай биш. Түвшин 4 түүнийг засна.
Эхлээд бүтэн зургийг харъя. Бид дараах бүтцийг үүсгэнэ:
fastapi-course/
├── venv/ (гар хүрэхгүй)
├── .env (нууц — git-д ордоггүй)
├── .env.example (загвар — git-д ордог)
├── .gitignore
├── main.py (app үүсгэх, холбох)
└── app/
├── __init__.py (хоосон)
├── config.py (тохиргоо унших)
├── models.py (Pydantic model-ууд)
├── dependencies.py (API key, хуудаслалт)
├── errors.py (exception handler-ууд)
└── routers/
├── __init__.py (хоосон)
└── notes.py (бүх endpoint)Найман файл, хоёр хавтас. Эхэндээ энэ нь хэт их санагдаж болно — далан мөр код найман файлд? Гэхдээ файл бүр нэг тодорхой үүрэгтэй, тэр нь гол зүйл. Ирээдүйд ном, хэрэглэгч нэмэхэд бүтэц бэлэн байна.
Хэрэв танд өмнөх хичээлүүдээс app/ хавтас байгаа бол түүнийг ашиглана; байхгүй бол шинээр үүсгэнэ.
Төслийн үндсэн хавтаст .env файл (байхгүй бол үүсгэнэ):
API_KEY=нууц-түлхүүр-12345
APP_NAME=Тэмдэглэлийн API
APP_VERSION=2.0.0
MAX_PAGE_SIZE=50.env.example файл (git-д орох загвар):
API_KEY=энд-өөрийн-түлхүүрээ-бичнэ
APP_NAME=Тэмдэглэлийн API
APP_VERSION=2.0.0
MAX_PAGE_SIZE=50.gitignore файл:
.env
venv/
__pycache__/
*.pycГурвуулаа хадгална.
Дөрвөн тохируулга байгааг анзаараарай. API_KEY бол нууц. APP_NAME, APP_VERSION бол нэр. MAX_PAGE_SIZE бол хязгаар. Гурван өөр төрлийн тохиргоо, бүгд нэг газар.
app хавтаст config.py файл үүсгэнэ:
python
# app/config.py
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["API_KEY"]
APP_NAME = os.getenv("APP_NAME", "API")
APP_VERSION = os.getenv("APP_VERSION", "1.0.0")
MAX_PAGE_SIZE = int(os.getenv("MAX_PAGE_SIZE", "50"))Хадгална.
Яагаад тусдаа файл вэ
Тохиргоог нэг файлд төвлөрүүлэх нь гурван ашигтай.
Нэгд, load_dotenv() нэг удаа дуудагдана. Хэрэв олон файлд тохиргоо уншвал load_dotenv()-ыг олон газар дуудах эрсдэлтэй. Энд нэг удаа, бүх төсөлд.
Хоёрт, хөрвүүлэлт нэг газар. MAX_PAGE_SIZE-ыг int()-ээр хөрвүүлж байгааг анзаараарай — Бүлэг 9-ийн Хичээл 1-ийн занга. Хөрвүүлэлт энд хийгдсэн тул бусад файл цэвэр int авна, текст биш.
Гуравт, ямар тохиргоо байгааг нэг харцаар харна. Шинэ хүн config.py-г нээгээд төслийн бүх тохируулгыг харна.
Бусад файлууд одоо from app.config import API_KEY гэж уншина — os.getenv дуудахгүй.
app хавтаст models.py:
python
# app/models.py
from pydantic import BaseModel
class NoteCreate(BaseModel):
text: str
priority: str = "энгийн"
done: bool = False
class NotePublic(BaseModel):
id: int
text: str
priority: str
done: bool
class ListParams(BaseModel):
skip: int
limit: int
search: str
priority: strХадгална.
Гурван model. Эхний хоёр нь v1-ээс танил: оролт (NoteCreate, id-гүй) болон гаралт (NotePublic, id-тэй).
ListParams нь шинэ — Бүлэг 8-ын Хичээл 2-оос. Энэ нь жагсаалтын параметрүүдийн бүтэц. Анзаараарай: түүнд default утга байхгүй, учир нь утгуудыг dependency функц бэлдэж, бүрэн дүүргэж өгнө.
app хавтаст dependencies.py:
python
# app/dependencies.py
from fastapi import Header, HTTPException
from app.config import API_KEY, MAX_PAGE_SIZE
from app.models import ListParams
def verify_api_key(x_api_key: str = Header()):
if x_api_key != API_KEY:
raise HTTPException(status_code=403, detail="Түлхүүр буруу байна")
return x_api_key
def list_params(
skip: int = 0,
limit: int = 10,
search: str = "",
priority: str = "",
) -> ListParams:
if limit > MAX_PAGE_SIZE:
limit = MAX_PAGE_SIZE
if limit < 1:
limit = 1
if skip < 0:
skip = 0
return ListParams(skip=skip, limit=limit, search=search, priority=priority)Хадгална.
Кодын задаргаа
Хоёр dependency, хоёр өөр үүрэг — Бүлэг 8-ын хоёр хичээлийн шууд үр дүн.
verify_api_key — хаалганы харуул (Хичээл 3). Түлхүүр буруу бол HTTPException шидэж, endpoint-ыг зогсооно.
list_params — бэлтгэл станц (Хичээл 2). Параметр цуглуулж, шалгаж, ListParams объект буцаана.
from app.config import API_KEY, MAX_PAGE_SIZE — тохиргоог config файлаас авч байна. MAX_PAGE_SIZE нь одоо .env-ээс ирж байгааг анзаараарай — өмнөх хичээлд 50 гэж кодонд бичсэн байсан. Одоо тохируулж болно.
Import-ийн урсгалыг ажиглаарай: dependencies.py нь config.py болон models.py-аас import хийж байна. Эсрэгээр биш. Бүлэг 7-т ярьсан "import нэг чиглэлд урсана" зарчим.
app хавтаст errors.py:
python
# app/errors.py
from fastapi import FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
def register_error_handlers(app: FastAPI) -> None:
@app.exception_handler(HTTPException)
def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={
"error": True,
"status": exc.status_code,
"message": exc.detail,
"path": str(request.url.path),
},
)
@app.exception_handler(RequestValidationError)
def validation_exception_handler(request: Request, exc: RequestValidationError):
errors = exc.errors()
first = errors[0] if errors else {}
field = first.get("loc", ["талбар"])[-1]
return JSONResponse(
status_code=422,
content={
"error": True,
"status": 422,
"message": f"'{field}' талбар буруу байна",
"path": str(request.url.path),
"details": errors,
},
)
@app.exception_handler(Exception)
def general_exception_handler(request: Request, exc: Exception):
print(f"АЛДАА: {request.url.path} — {type(exc).__name__}: {exc}")
return JSONResponse(
status_code=500,
content={
"error": True,
"status": 500,
"message": "Серверт алдаа гарлаа. Дараа дахин оролдоно уу.",
"path": str(request.url.path),
},
)Хадгална.
Шинэ загвар: функц дотор handler
Энд нэг шинэ зүйл байна. Өмнөх хичээлд handler-үүд шууд @app.exception_handler(...) гэж бичигдсэн байсан. Гэхдээ одоо app объект нь main.py-д байгаа, errors.py-д биш.
Шийдэл: app-ыг параметр болгон авдаг функц бичих.
python
def register_error_handlers(app: FastAPI) -> None:
@app.exception_handler(HTTPException)
def http_exception_handler(...):
...register_error_handlers(app) гэж дуудахад доторх бүх decorator ажиллаж, handler-үүд тэр app-д бүртгэгдэнэ.
Энэ бол Курс 2-ын Бүлэг 10-ын функц дотор функц санаа. Гаднах функц нь app-ыг хүлээж авдаг; дотоод функцууд нь handler. Decorator нь дотоод функцуудыг гаднаас ирсэн app-д холбоно.
Эхэндээ бага зэрэг хийсвэр санагдаж болно, гэхдээ энэ нь FastAPI төслүүдэд түгээмэл загвар: тохируулгыг функц болгож, main.py-аас дуудах. Ингэснээр main.py цэвэрхэн үлддэг.
-> None нь type hint — энэ функц юу ч буцаадаггүй, зөвхөн бүртгэдэг.
app/routers хавтаст notes.py:
python
# app/routers/notes.py
from fastapi import APIRouter, Depends, HTTPException
from app.dependencies import list_params, verify_api_key
from app.models import ListParams, NoteCreate, NotePublic
router = APIRouter(prefix="/notes", tags=["Тэмдэглэл"])
notes: list[dict] = []
next_id = 1
def find_note(note_id: int) -> dict:
for note in notes:
if note["id"] == note_id:
return note
raise HTTPException(status_code=404, detail="Тэмдэглэл олдсонгүй")
@router.get("", response_model=list[NotePublic])
def get_notes(params: ListParams = Depends(list_params)):
result = notes
if params.search:
term = params.search.lower()
result = [n for n in result if term in n["text"].lower()]
if params.priority:
result = [n for n in result if n["priority"] == params.priority]
return result[params.skip : params.skip + params.limit]
@router.get("/{note_id}", response_model=NotePublic)
def get_note(note_id: int):
return find_note(note_id)
@router.post(
"",
status_code=201,
response_model=NotePublic,
dependencies=[Depends(verify_api_key)],
)
def create_note(note: NoteCreate):
global next_id
new_note = note.model_dump()
new_note["id"] = next_id
notes.append(new_note)
next_id += 1
return new_note
@router.put(
"/{note_id}",
response_model=NotePublic,
dependencies=[Depends(verify_api_key)],
)
def update_note(note_id: int, note: NoteCreate):
existing = find_note(note_id)
existing["text"] = note.text
existing["priority"] = note.priority
existing["done"] = note.done
return existing
@router.delete(
"/{note_id}",
status_code=204,
dependencies=[Depends(verify_api_key)],
)
def delete_note(note_id: int):
note = find_note(note_id)
notes.remove(note)
return NoneХадгална.
Кодын задаргаа
find_note туслах функц. v1-д "хайж олох, олдохгүй бол 404" гэсэн логик гурван endpoint дээр давтагдаж байсан. Одоо нэг функцэд гаргалаа.
Анзаараарай: find_note нь олдвол тэмдэглэлийг буцаана, олдохгүй бол HTTPException шидэнэ. Тиймээс endpoint-ууд ингэж бичигдэнэ:
python
def get_note(note_id: int):
return find_note(note_id)Ганц мөр. Хэрэв олдохгүй бол find_note дотроос exception шидэгдэж, endpoint хүртэл хүрэхгүй. Курс 2-ын Бүлэг 13-ын raise-ийн санаа энд бодит ашиг өгч байна: алдааг гүн функцээс шидэхэд дээшээ өөрөө дамждаг.
find_note бол dependency биш — ердийн туслах функц. Бид түүнийг өөрсдөө дуудаж байна, FastAPI биш. Бүлэг 8-ын Хичээл 2-т ярьсан ялгаа.
delete_note илүү цэвэрхэн боллоо. v1-д enumerate + pop(i) байсан. Одоо find_note объектыг олдог тул notes.remove(note) хангалттай — индекс хэрэггүй.
Хамгаалалт. POST, PUT, DELETE гурав нь dependencies=[Depends(verify_api_key)]-тэй. Хоёр GET нь хамгаалалтгүй. Унших нээлттэй, бичих хаалттай.
Хуудаслалт. get_notes нь Depends(list_params) ашиглаж байна. Хайлт, priority шүүлт, skip/limit — бүгд нэг dependency-ээс.
Төслийн үндсэн хавтаст main.py-г бүхэлд нь солино:
python
# main.py
from fastapi import FastAPI
from app.config import APP_NAME, APP_VERSION
from app.errors import register_error_handlers
from app.routers import notes
app = FastAPI(
title=APP_NAME,
version=APP_VERSION,
description="Тэмдэглэл хадгалах API (v2 — олон файлт бүтэц, API key хамгаалалт)",
)
register_error_handlers(app)
app.include_router(notes.router)Хадгална.
Кодын задаргаа
Арван мөр орчим. main.py нь одоо зөвхөн угсрах ажил хийж байна: app үүсгэх, handler бүртгэх, router холбох.
Логик байхгүй. Endpoint байхгүй. Model байхгүй. Бүх зүйл app/ дор.
Энэ бол сайн main.py хэрхэн харагддагийн жишээ. Хэн ч түүнийг нээгээд секундын дотор "энэ бол Тэмдэглэлийн API, нэг router-тай, алдааны handler-тэй" гэж ойлгоно.
register_error_handlers(app) — router холбохоос өмнө дуудсан. Дараалал нь энд чухал биш, гэхдээ handler-ыг эхэнд бүртгэх нь уншихад логик.
Терминал төслийн үндсэн хавтаст байгаа эсэхийг шалгана (fastapi-course/, app/ дотор биш). Дараа нь:
fastapi dev main.pyХэрэв .env шинээр өөрчлөгдсөн бол сервер гараар дахин асаах шаардлагатай.
Шалгах цэг: /docs
http://127.0.0.1:8000/docsДээд талд Тэмдэглэлийн API 2.0.0 — .env-ээс уншсан нэр, хувилбар. Доор нь тайлбар.
Endpoint-үүд Тэмдэглэл гэсэн tag дор бүлэглэгдсэн:
Тэмдэглэл
GET /notes
POST /notes
GET /notes/{note_id}
PUT /notes/{note_id}
DELETE /notes/{note_id}GET /notes дээр товшвол дөрвөн query parameter (skip, limit, search, priority) — dependency-ээс.
POST /notes дээр товшвол x-api-key header талбар — хамгаалалтаас.
Одоо бүх зүйлийг дараалан туршъя. Энэ бол v2 зөв ажиллаж байгааг батлах бүрэн мөчлөг.
1. Хоосон жагсаалт
http://127.0.0.1:8000/notesХариу (статус 200):
json
[]2. Түлхүүргүй үүсгэх — амжилтгүй
/docs -> POST /notes -> Try it out. x-api-key хоосон, body:
json
{"text": "Тест"}Хариу (статус 422):
json
{
"error": true,
"status": 422,
"message": "'x-api-key' талбар буруу байна",
"path": "/notes",
"details": [
{
"type": "missing",
"loc": ["header", "x-api-key"],
"msg": "Field required",
"input": null
}
]
}Таны шинэ алдааны бүтэц ажиллаж байна. error, status, message, path — бүгд байна. message нь монголоор, ойлгомжтой. details нь техникийн дэлгэрэнгүй.
3. Буруу түлхүүр — амжилтгүй
x-api-key талбарт буруу гэж бичээд Execute.
Хариу (статус 403):
json
{
"error": true,
"status": 403,
"message": "Түлхүүр буруу байна",
"path": "/notes"
}Ижил бүтэц, өөр статус. Тогтвортой.
4. Зөв түлхүүр — амжилттай
x-api-key талбарт нууц-түлхүүр-12345, body:
json
{"text": "Сүү авах", "priority": "чухал"}Хариу (статус 201):
json
{"id":1,"text":"Сүү авах","priority":"чухал","done":false}Дахин хоёр тэмдэглэл нэмнэ:
json
{"text": "Номоо буцаах"}json
{"text": "Тайлан бичих", "priority": "яаралтай"}5. Жагсаалт ба шүүлт
http://127.0.0.1:8000/notesГурван тэмдэглэл.
http://127.0.0.1:8000/notes?priority=чухалНэг тэмдэглэл (Сүү авах).
http://127.0.0.1:8000/notes?search=бичихНэг тэмдэглэл (Тайлан бичих).
http://127.0.0.1:8000/notes?limit=2Хоёр тэмдэглэл.
6. Хамгаалалтын хязгаар ажиллаж байна
http://127.0.0.1:8000/notes?limit=99999Гурван тэмдэглэл бүгд (MAX_PAGE_SIZE=50 тул хязгаарлагдсан, гурав нь 50-аас бага тул бүгд ирнэ).
.env-д MAX_PAGE_SIZE=2 болгож өөрчлөөд серверээ дахин асаагаад дахин туршвал зөвхөн хоёр ирнэ. Тохиргоо кодыг өөрчлөхгүйгээр зан төлөвийг өөрчилж байна.
7. Нэг тэмдэглэл ба 404
http://127.0.0.1:8000/notes/1Хариу (статус 200): эхний тэмдэглэл.
http://127.0.0.1:8000/notes/99Хариу (статус 404):
json
{
"error": true,
"status": 404,
"message": "Тэмдэглэл олдсонгүй",
"path": "/notes/99"
}find_note дотроос шидэгдсэн exception нь handler хүрч, шинэ бүтцээр гарлаа.
8. Засах
/docs -> PUT /notes/{note_id}. Path 1, түлхүүр зөв, body:
json
{"text": "Сүү ба талх авах", "priority": "чухал", "done": true}Хариу (статус 200):
json
{"id":1,"text":"Сүү ба талх авах","priority":"чухал","done":true}9. Устгах
/docs -> DELETE /notes/{note_id}. Path 2, түлхүүр зөв.
Хариу (статус 204): хоосон.
GET-ээр батлана — хоёр тэмдэглэл үлдсэн.
Түлхүүргүй DELETE — 422. Байхгүй id-г DELETE — 404 (шинэ бүтцээр).
Бүх мөчлөг ажиллаж байна.
Одоо бидний хийсэн ажлыг эргэн харъя.
Бүтэц. Нэг файл -> найман файл, хоёр хавтас. Файл бүр нэг үүрэгтэй: тохиргоо, model, dependency, алдаа, endpoint, угсралт.
Router. @app.get -> APIRouter prefix болон tag-тай. /docs хуудас бүлэглэгдсэн.
Хамгаалалт. Байхгүйгээс -> API key-ээр бичих үйлдэл хамгаалагдсан. Унших нээлттэй.
Тохиргоо. Кодонд бичсэнээс -> .env файлд. Нууц кодоос гарсан, .gitignore-оор хамгаалагдсан.
Алдаа. FastAPI-ийн стандартаас -> нэгтгэсэн, монгол мессежтэй, тогтвортой бүтэц.
Давталт. find_note туслах функц гурван газрын давталтыг арилгасан. list_params dependency параметрийн давталтыг арилгасан.
Гэхдээ endpoint-ийн зан төлөв бараг ижил. Хэрэглэгч ижил хаяг руу, ижил өгөгдлөөр хандаж, ижил үр дүн авна. Зөвхөн хамгаалалт болон алдааны хэлбэр өөрчлөгдсөн.
Энэ бол refactoring-ийн жинхэнэ утга: гаднаас ижил, дотроос илүү сайн.
Энэ бүтээн байгуулалтад Түвшин 3-ын бүх зүйл ашиглагдсан.
Бүлэг 7: APIRouter, prefix, tags, олон файлт бүтэц, package import, import-ийн чиглэл.
Бүлэг 8: Depends (өгөгдөл бэлдэх), ListParams model dependency, Header, API key шалгалт, dependencies=[...] бичлэг.
Бүлэг 9: .env, load_dotenv, os.environ ба os.getenv, int() хөрвүүлэлт, .gitignore, exception handler, JSONResponse.
Мөн Түвшин 1-2-оос: бүрэн CRUD, Pydantic оролт-гаралтын model, status code, HTTPException, list comprehension, slicing.
Эдгээр нь заавал биш.
Нэгдүгээр өргөтгөл: хоёр дахь router. app/routers/tags.py үүсгэж, /tags prefix-тэй энгийн CRUD бичээд main.py-д холбоно. Бүтэц шинэ нөөцийг хэр амархан даахыг мэдрэх сайн дасгал.
Хоёрдугаар өргөтгөл: статистик endpoint. GET /notes/stats нэмж, нийт тоо, дууссаны тоо, priority бүрийн тоог буцаана. Санамж: route ordering — /notes/stats нь /notes/{note_id}-ийн өмнө байх ёстой.
Гуравдугаар өргөтгөл: тохиргоог өргөтгөх. .env-д DEFAULT_PRIORITY=энгийн нэмж, config.py-д уншиж, NoteCreate model-ын default болгож ашиглана.
Одоо шударга дүгнэлт хийе. Таны API мэргэжлийн бүтэцтэй, хамгаалалттай, тохируулж болдог боллоо. Гэхдээ нэг том дутагдал хэвээр байна.
Серверээ унтраа (Ctrl+C), дахин асаа, дараа нь:
http://127.0.0.1:8000/notesХариу:
json
[]Бүх тэмдэглэл дахин алга болсон.
Бид v1-д яг үүнтэй тулгарсан. v2 нь бүтцийг сайжруулсан боловч хадгалалтад огт гар хүрээгүй. Тэмдэглэлүүд одоо ч notes: list[dict] = [] гэсэн Python жагсаалтад, санах ойд амьдарч байна.
Энэ нь v2-ийн алдаа биш — зориудаар. Нэг удаад нэг зүйл сайжруулах нь refactoring-ийн зөв арга. Бид бүтцийг цэгцэлсэн; хадгалалт нь дараагийн ажил.
Мөн анзаараарай: v3-т өгөгдлийн сан нэмэхэд зөвхөн notes.py файл өөрчлөгдөнө. config.py, errors.py, main.py бараг хэвээр үлдэнэ. Энэ бол сайн бүтцийн ашиг: өөрчлөлт нэг газарт хязгаарлагдана. Хэрэв бүх зүйл нэг файлд байсан бол бүхэл файлыг дахин бичих байсан.
v2 бол refactoring — зан төлөв бараг ижил, бүтэц болон хамгаалалт өөрчлөгдсөн.
Найман файл, тус бүр нэг үүрэгтэй: config, models, dependencies, errors, router, main.
config.py нь load_dotenv()-ыг нэг удаа дуудаж, хөрвүүлэлтийг (int()) төвлөрүүлнэ.
errors.py-д handler-үүдийг функц дотор бичиж, main.py-аас app-ыг дамжуулна.
find_note туслах функц гурван газрын давталтыг арилгасан; raise нь гүнээс дээш дамжина.
Бичих endpoint dependencies=[Depends(verify_api_key)]-тэй; унших нээлттэй.
main.py арван мөр — зөвхөн угсарна, логик агуулахгүй.
Серверийг үргэлж үндсэн хавтаснаас ажиллуул.
Үлдсэн хязгаар: санах ой түр зуурынх — сервер унтраахад бүх өгөгдөл алга.
Түвшин 3 дууслаа. Таны API одоо мэргэжлийн бүтэцтэй, олон файлт, хамгаалалттай, тохируулж болдог. Ямар ч бодит FastAPI төсөл ойролцоогоор ийм харагддаг.
Түвшин 4 бүхэлдээ үлдсэн том дутагдалд зориулагдана: байнгын хадгалалт. Бид эхлээд өгөгдлийн сан гэж юу болох, яагаад файл хангалтгүй болдгийг ойлгоно (Бүлэг 10). Дараа нь SQLModel сурч, Python class-ыг өгөгдлийн сангийн хүснэгт болгож, мөр нэмж, унших, засах, устгах болно (Бүлэг 11). Эцэст нь тэдгээрийг API-даа залгаж, Тэмдэглэлийн API v3 бүтээнэ (Бүлэг 12) — тэнд серверээ унтраагаад дахин асаахад тэмдэглэлүүд газраасаа хөдлөхгүй байхыг та өөрийн нүдээр харна. Тэр мөч бол энэ сургалтын хамгийн чухал мөчүүдийн нэг бөгөөд бид түүнийг зохих ёсоор тэмдэглэнэ.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.