Ачааллж байна...
Энэ бол Тэмдэглэлийн API-ийн эцсийн хувилбар.
Түвшин 2-т бид v1 бүтээсэн: нэг файл, бүрэн CRUD, санах ойд. Түвшин 3-т v2 бүтээсэн: олон файлт мэргэжлийн бүтэц, API key хамгаалалт, .env тохиргоо, нэгтгэсэн алдааны handler — гэхдээ хадгалалт нь санах ойд хэвээр.
Одоо v3. Бид v2-ийн бүх бүтцийг хадгалж, санах ойн жагсаалтыг жинхэнэ өгөгдлийн сангаар солино.
Хичээлийн төгсгөлд серверээ унтраагаад дахин асаахад тэмдэглэлүүд газраасаа хөдлөхгүй байхыг та өөрийн нүдээр харна. Тэр бол бүх сургалтын турш барьж ирсэн утас тайлагдах мөч юм.
v2 (Түвшин 3) | v3 (Түвшин 4) | |
|---|---|---|
Хадгалалт |
| SQLite өгөгдлийн сан |
id |
| Өгөгдлийн сан өгнө |
Хайлт | list comprehension |
|
Хуудаслалт | slicing |
|
Бүтэц | 8 файл, 2 хавтас | Ижил + |
Хамгаалалт | API key | Ижил |
Тохиргоо |
| Ижил |
Алдаа | Нэгтгэсэн handler | Ижил |
Баруун баганын сүүлийн гурван мөрийг анзаараарай: өөрчлөгдөхгүй.
Энэ бол Түвшин 3-ын төгсгөлд амласан зүйл: сайн бүтэцтэй код өөрчлөгдөхөд өөрчлөлт нэг газарт хязгаарлагдана. config.py, errors.py, dependencies.py (хэсэгчлэн), main.py бараг хэвээр үлдэнэ.
fastapi-course/
├── venv/
├── .env
├── .env.example
├── .gitignore
├── notes.db (шинэ — өгөгдлийн сан, git-д ордоггүй)
├── main.py
└── app/
├── __init__.py
├── config.py (бага зэрэг өөрчлөгдөнө)
├── database.py (ШИНЭ — engine, session)
├── models.py (өөрчлөгдөнө — SQLModel)
├── dependencies.py (бага зэрэг өөрчлөгдөнө)
├── errors.py (ӨӨРЧЛӨГДӨХГҮЙ)
└── routers/
├── __init__.py
└── notes.py (ихээхэн өөрчлөгдөнө)Нэг шинэ файл: database.py. Нэг шинэ файл нэмж, хоёр файлыг ихээхэн засаж, бусдыг бараг хэвээр үлдээнэ.
.env файлдаа өгөгдлийн сангийн хаяг нэмнэ:
API_KEY=нууц-түлхүүр-12345
APP_NAME=Тэмдэглэлийн API
APP_VERSION=3.0.0
MAX_PAGE_SIZE=50
DATABASE_URL=sqlite:///notes.db.env.example файлд ч мөн:
API_KEY=энд-өөрийн-түлхүүрээ-бичнэ
APP_NAME=Тэмдэглэлийн API
APP_VERSION=3.0.0
MAX_PAGE_SIZE=50
DATABASE_URL=sqlite:///notes.dbХадгална.
Яагаад DATABASE_URL нь тохиргоонд байх ёстой вэ
Бүлэг 11-ийн Хичээл 2-т бид create_engine("sqlite:///notes.db") гэж кодонд бичсэн. Одоо түүнийг .env рүү зөөж байна. Гурван шалтгаантай.
Нэгд, орчин бүр өөр. Таны компьютер дээр notes.db; бодит серверт өөр зам, эсвэл огт өөр өгөгдлийн сан.
Хоёрт, PostgreSQL руу шилжих зам. Хэрэв хожим шилжвэл зөвхөн энэ мөр өөрчлөгдөнө:
DATABASE_URL=postgresql://хэрэглэгч:нууц@хаяг/өгөгдлийн_санКодод гар хүрэхгүй. Бүлэг 12-ын Хичээл 1-т ярьсан "endpoint нь engine-ээс салсан" зарчмын үргэлжлэл.
Гуравт, нууц агуулж болно. PostgreSQL-ийн холболтын мөрөнд нууц үг байдаг. Тэр нь кодонд байх ёсгүй — .env-д байх ёстой.
.gitignore шалгах
.env
venv/
__pycache__/
*.pyc
*.db*.db мөр байгаа эсэхийг шалгаарай. Одоо энэ нь бодит утгатай — notes.db файл үүсэх гэж байна.
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"))
DATABASE_URL = os.environ["DATABASE_URL"]Хадгална.
os.environ[...] ашигласныг анзаараарай — DATABASE_URL нь заавал. Өгөгдлийн сангийн хаяггүй бол программ ажиллах утгагүй тул дутуу бол шууд унах нь зөв (Бүлэг 9-ийн Хичээл 1-ийн зарчим).
app хавтаст database.py файл үүсгэнэ:
python
# app/database.py
from sqlmodel import SQLModel, Session, create_engine
from app.config import DATABASE_URL
engine = create_engine(DATABASE_URL)
def create_db_and_tables() -> None:
SQLModel.metadata.create_all(engine)
def get_session():
with Session(engine) as session:
yield sessionХадгална.
Яагаад тусдаа файл вэ
Өгөгдлийн сангийн бүх зүйлийг нэг газар төвлөрүүлж байна: engine, хүснэгт үүсгэх, session dependency.
Гурван ашигтай.
Нэгд, engine нэг л удаа үүснэ. Хэрэв олон файлд create_engine дуудвал олон холболтын сан үүсч, нөөц үрэгдэнэ. Энд нэг удаа, бүх төсөлд.
Хоёрт, router-ууд өгөгдлийн сангийн нарийн ширийнийг мэдэхгүй. Тэд зөвхөн from app.database import get_session гэж бичнэ. Engine хаанаас ирснийг мэдэхгүй.
Гуравт, солиход хялбар. PostgreSQL руу шилжвэл зөвхөн энэ файл (болон .env) хамаарна.
Import-ийн урсгал
database.py нь config.py-аас import хийж байна. Эсрэгээр биш.
Бүлэг 7-т тогтоосон дүрэм: import нэг чиглэлд урсана. Одоогийн шатлал:
config.py (юунаас ч хамаарахгүй)
↓
database.py (config-оос)
models.py (юунаас ч хамаарахгүй)
↓
dependencies.py (config, models-оос)
↓
routers/notes.py (бүгдээс)
↓
main.py (бүгдээс)Дээрээс доош. Цикл байхгүй.
app/models.py-г бүхэлд нь солино:
python
# app/models.py
from sqlmodel import SQLModel, Field
class NoteCreate(SQLModel):
text: str
priority: str = "энгийн"
done: bool = False
class Note(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
text: str
priority: str = "энгийн"
done: bool = False
class NotePublic(SQLModel):
id: int
text: str
priority: str
done: bool
class ListParams(SQLModel):
skip: int
limit: int
search: str
priority: strХадгална.
Юу өөрчлөгдсөн бэ
BaseModel -> SQLModel. Бүх class одоо SQLModel-ээс өвлөж байна. pydantic import алга болсон.
Note нь table=True авсан — одоо тэр бол хүснэгт.
ListParams нь SQLModel-ээс өвлөж байна — table биш, зөвхөн дотоод бүтэц. Бүлэг 8-ын Хичээл 2-оос танил.
Бусад талбарууд, default утгууд, бүтэц бүгд хэвээр. Pydantic-ээс SQLModel руу шилжих нь бараг өвдөлтгүй — учир нь SQLModel нь Pydantic дээр баригдсан.
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)Хадгална.
Энэ файл v2-оос огт өөрчлөгдөөгүй.
Анзаараарай: list_params нь өгөгдлийн сангийн тухай юу ч мэдэхгүй. Тэр зөвхөн параметр цуглуулж, шалгаж, буцаана. v2-т тэдгээр параметрүүд Python slicing-д ашиглагдаж байсан; v3-т SQL LIMIT/OFFSET-д ашиглагдана. Dependency нь ижил хэвээр.
Энэ бол Бүлэг 8-ын Хичээл 2-т амласан зүйл: "хэрэгжүүлэлт өөрчлөгдөхөд интерфейс хэвээр үлддэг".
session dependency нь database.py-д байгаа тул энд байхгүй. Хоёр өөр төрлийн dependency, хоёр өөр файлд: хамгаалалт/параметр энд, өгөгдлийн сан тэнд.
Гар хүрэхгүй. v2-ийн файл яг хэвээр ажиллана.
Хэрэв танд байхгүй бол Бүлэг 9-ийн Хичээл 3-аас хуулж авна уу. Агуулга нь:
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),
},
)Энэ файл өгөгдлийн сангийн тухай юу ч мэдэхгүй. Алдаа боловсруулах нь хадгалалтаас бүрэн хамааралгүй давхарга — тиймээс өөрчлөгдөх шаардлагагүй.
Мөн нэг далд ашиг: хэрэв өгөгдлийн сангийн алдаа гарвал (жишээ нь файл байхгүй, хүснэгт олдохгүй) Exception handler түүнийг барьж, хэрэглэгчид ерөнхий 500 мессеж өгнө. Дотоод SQL алдааны мессеж гадагш гарахгүй — Бүлэг 9-т ярьсан аюулгүй байдлын зарчим.
app/routers/notes.py-г бүхэлд нь солино:
python
# app/routers/notes.py
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from app.database import get_session
from app.dependencies import list_params, verify_api_key
from app.models import ListParams, Note, NoteCreate, NotePublic
router = APIRouter(prefix="/notes", tags=["Тэмдэглэл"])
def find_note(note_id: int, session: Session) -> Note:
note = session.get(Note, note_id)
if note is None:
raise HTTPException(status_code=404, detail="Тэмдэглэл олдсонгүй")
return note
@router.get("", response_model=list[NotePublic])
def get_notes(
params: ListParams = Depends(list_params),
session: Session = Depends(get_session),
):
statement = select(Note)
if params.search:
statement = statement.where(Note.text.contains(params.search))
if params.priority:
statement = statement.where(Note.priority == params.priority)
statement = statement.offset(params.skip).limit(params.limit)
return session.exec(statement).all()
@router.get("/{note_id}", response_model=NotePublic)
def get_note(note_id: int, session: Session = Depends(get_session)):
return find_note(note_id, session)
@router.post(
"",
status_code=201,
response_model=NotePublic,
dependencies=[Depends(verify_api_key)],
)
def create_note(note: NoteCreate, session: Session = Depends(get_session)):
db_note = Note.model_validate(note)
session.add(db_note)
session.commit()
session.refresh(db_note)
return db_note
@router.put(
"/{note_id}",
response_model=NotePublic,
dependencies=[Depends(verify_api_key)],
)
def update_note(
note_id: int,
note: NoteCreate,
session: Session = Depends(get_session),
):
db_note = find_note(note_id, session)
db_note.text = note.text
db_note.priority = note.priority
db_note.done = note.done
session.commit()
session.refresh(db_note)
return db_note
@router.delete(
"/{note_id}",
status_code=204,
dependencies=[Depends(verify_api_key)],
)
def delete_note(note_id: int, session: Session = Depends(get_session)):
db_note = find_note(note_id, session)
session.delete(db_note)
session.commit()
return NoneХадгална.
Юу өөрчлөгдсөн бэ
notes: list[dict] болон next_id алга болсон. Санах ойн хадгалалт байхгүй. Тоолуур байхгүй — өгөгдлийн сан id өгнө.
find_note нь session хүлээж авдаг болсон:
python
def find_note(note_id: int, session: Session) -> Note:
note = session.get(Note, note_id)
if note is None:
raise HTTPException(status_code=404, detail="Тэмдэглэл олдсонгүй")
return notev2-т тэр глобал жагсаалтыг хайдаг байсан. Одоо session.get-ыг ашиглаж, None эсэхийг шалгана.
Логик нь яг ижил: ол, олдохгүй бол 404 шид. Зөвхөн эх сурвалж өөр.
Мөн анзаараарай: find_note нь dependency биш — ердийн туслах функц. Session-ыг параметрээр авч байна, Depends ашиглаагүй. Бүлэг 8-ын Хичээл 2-т ярьсан ялгаа: Depends() дотор зөвхөн хүсэлтээс өгөгдөл авдаг функц; дотоод туслах функцийг та өөрөө дуудна.
Endpoint бүр session: Session = Depends(get_session) авдаг болсон.
Хайлт нь .where() болсон:
python
# v2
result = [n for n in result if term in n["text"].lower()]
# v3
statement = statement.where(Note.text.contains(params.search))Хуудаслалт нь .offset().limit() болсон:
python
# v2
return result[params.skip : params.skip + params.limit]
# v3
statement = statement.offset(params.skip).limit(params.limit)Юу өөрчлөгдөөгүй вэ
Router-ийн бүтэц — prefix, tag хэвээр.
Хамгаалалт — dependencies=[Depends(verify_api_key)] гурван endpoint дээр яг хэвээр.
response_model — бүгд хэвээр.
Status code — 201, 204, 404 бүгд хэвээр.
find_note загвар — гурван газарт давталтыг арилгах зарчим хэвээр.
Гаднаас харахад API яг ижил ажиллана. Дотор нь бүх зүйл өөрчлөгдсөн.
main.py-г солино:
python
# main.py
from fastapi import FastAPI
from app.config import APP_NAME, APP_VERSION
from app.database import create_db_and_tables
from app.errors import register_error_handlers
from app.routers import notes
app = FastAPI(
title=APP_NAME,
version=APP_VERSION,
description="Тэмдэглэл хадгалах API (v3 — өгөгдлийн сантай)",
)
register_error_handlers(app)
app.include_router(notes.router)
@app.on_event("startup")
def on_startup():
create_db_and_tables()Хадгална.
Хоёр мөр нэмэгдсэн: create_db_and_tables import болон startup event. Бусад нь v2-ийн хэвээр.
main.py арван таван мөр. Одоо ч зөвхөн угсарч байна: app үүсгэх, handler бүртгэх, router холбох, эхлэхэд хүснэгт үүсгэх.
Терминал төслийн үндсэн хавтаст байгаа эсэхийг шалгана. Хэрэв өмнөх хичээлээс notes.db файл байгаа бол устгаж, цэвэр эхлэх нь зүйтэй.
fastapi dev main.pyСервер асахад create_db_and_tables ажиллаж, notes.db файл үүснэ.
Файлын жагсаалтаа хараарай — notes.db гарч ирсэн байх ёстой.
Одоо бүх зүйлийг дараалан туршъя.
1. /docs
http://127.0.0.1:8000/docsДээд талд Тэмдэглэлийн API 3.0.0. Endpoint-үүд Тэмдэглэл tag дор бүлэглэгдсэн.
POST /notes дээр товшвол Request body нь NoteCreate — id байхгүй. Мөн x-api-key header талбар байна.
2. Хоосон жагсаалт
http://127.0.0.1:8000/notesХариу:
json
[]3. Түлхүүргүй үүсгэх
/docs -> POST /notes, x-api-key хоосон, body:
json
{"text": "Тест"}Хариу (статус 422):
json
{
"error": true,
"status": 422,
"message": "'x-api-key' талбар буруу байна",
"path": "/notes",
"details": [...]
}Хамгаалалт болон алдааны handler хоёулаа ажиллаж байна — v2-оос өөрчлөгдөөгүй.
4. Буруу түлхүүр
x-api-key талбарт буруу:
Хариу (статус 403):
json
{
"error": true,
"status": 403,
"message": "Түлхүүр буруу байна",
"path": "/notes"
}5. Зөв түлхүүрээр гурван тэмдэглэл
x-api-key талбарт нууц-түлхүүр-12345, дараалан:
json
{"text": "Сүү авах", "priority": "чухал"}json
{"text": "Номоо буцаах"}json
{"text": "Тайлан бичих", "priority": "яаралтай"}Хариу (статус 201):
json
{"id":1,"text":"Сүү авах","priority":"чухал","done":false}id нь 1, 2, 3 — өгөгдлийн сан өгсөн.
6. Хайлт ба шүүлт
http://127.0.0.1:8000/notesГурван тэмдэглэл.
http://127.0.0.1:8000/notes?search=бичихНэг тэмдэглэл (Тайлан бичих).
http://127.0.0.1:8000/notes?priority=чухалНэг тэмдэглэл (Сүү авах).
http://127.0.0.1:8000/notes?limit=2Хоёр тэмдэглэл.
http://127.0.0.1:8000/notes?skip=1&limit=2Хоёр дахь, гурав дахь.
Бүх шүүлт өгөгдлийн санд хийгдэж байна.
7. Хамгаалалтын хязгаар
http://127.0.0.1:8000/notes?limit=99999Гурван тэмдэглэл (MAX_PAGE_SIZE=50 тул хязгаарлагдсан).
.env-д MAX_PAGE_SIZE=2 болгож, серверээ дахин асаагаад дахин туршвал хоёр л ирнэ. Тохиргоо кодыг өөрчлөхгүйгээр зан төлөвийг өөрчилж байна.
Дараа нь буцааж 50 болгоно.
8. Нэг тэмдэглэл ба 404
http://127.0.0.1:8000/notes/1Хариу (200): эхний тэмдэглэл.
http://127.0.0.1:8000/notes/999Хариу (404):
json
{
"error": true,
"status": 404,
"message": "Тэмдэглэл олдсонгүй",
"path": "/notes/999"
}find_note-оос шидэгдсэн exception нь handler хүрч, нэгтгэсэн бүтцээр гарлаа.
9. Засах
/docs -> PUT /notes/{note_id}. Path 1, түлхүүр зөв, body:
json
{"text": "Сүү ба талх авах", "priority": "чухал", "done": true}Хариу (200):
json
{"id":1,"text":"Сүү ба талх авах","priority":"чухал","done":true}10. Устгах
/docs -> DELETE /notes/{note_id}. Path 2, түлхүүр зөв.
Хариу (204): хоосон.
http://127.0.0.1:8000/notesХоёр тэмдэглэл (id 1 болон 3).
Дахин DELETE /notes/2 -> 404.
Одоо энэ сургалтын нэг том мөч.
Одоогийн байдлыг санаж авна уу: хоёр тэмдэглэл байгаа, id 1 (засварласан, done=true) болон id 3.
Терминал дээр Ctrl+C дарна. Сервер зогсоно.
Хэдэн секунд хүлээгээрэй. Программ бүрэн зогссон. Санах ой цэвэрлэгдсэн. Python процесс байхгүй.
Одоо дахин асаана:
fastapi dev main.pyДараа нь:
http://127.0.0.1:8000/notesХариу:
json
[
{"id":1,"text":"Сүү ба талх авах","priority":"чухал","done":true},
{"id":3,"text":"Тайлан бичих","priority":"яаралтай","done":false}
]Тэмдэглэлүүд байрандаа байна.
Засварласан тэмдэглэл засварласан хэвээр. Устгасан тэмдэглэл устсан хэвээр. id 2 дутуу — устгагдсан тул дахин ашиглагдаагүй.
Түвшин 2-ын төгсгөлд бид ижил туршилт хийж, [] харсан. Түвшин 3-ын төгсгөлд дахин []. Одоо — өгөгдөл.
Энэ бол Бүлэг 6-ын Хичээл 3-т эхэлсэн утас. Тэнд би "серверээ унтраа, тэмдэглэл алга болно — Түвшин 4 үүнийг засна" гэж бичсэн. Одоо тэр амлалт биелэв.
Таны компьютер дээрх notes.db файлд таны өгөгдөл байна. Та түүнийг хуулж, өөр компьютерт зөөж, тэндээс үргэлжлүүлж болно. Компьютераа унтраагаад маргааш асаахад тэдгээр байрандаа байх болно.
Энэ бол жинхэнэ программ хангамжийн шинж юм.
v3-д Түвшин 4-ийн бүх зүйл ашиглагдсан.
Бүлэг 10: өгөгдлийн сан яагаад хэрэгтэй, SQLite, SQL уншиж таних.
Бүлэг 11: SQLModel, table=True, create_engine, create_all, Session, add/commit/refresh, select/where/offset/limit, get, delete.
Бүлэг 12: session dependency (yield), гурван model-ын загвар, model_validate, CRUD endpoint-ууд.
Мөн Түвшин 1-3-аас: router, tag, Depends, API key, .env, exception handler, response_model, HTTPException, бүрэн CRUD.
Долоон бүлгийн мэдлэг нэг программд.
Нэгдүгээр өргөтгөл: эрэмбэлэлт. list_params-д sort_desc: bool = False нэмээд, router-т:
python
if params.sort_desc:
statement = statement.order_by(Note.id.desc())ListParams model-д ч талбар нэмэхээ мартуузай.
Хоёрдугаар өргөтгөл: тоолуур endpoint. GET /notes/count нэмж, нийт тоог буцаана. Санамж: select(Note)-ийн бүх үр дүнг len() хийж болно, гэхдээ илүү зөв нь SQL-ын COUNT — тэр нь from sqlmodel import func шаардана. Мөн route ordering: /notes/count нь /notes/{note_id}-ийн өмнө байх ёстой (Бүлэг 2-ын занга).
Гуравдугаар өргөтгөл: огноо. Model-д created_at: datetime = Field(default_factory=datetime.now) нэмээд, тэмдэглэл үүсгэсэн цагийг хадгална. Санамж: model өөрчлөх бүрд .db файлыг устгана (Бүлэг 11-ийн Хичээл 2).
Шударга дүгнэлт хийе. v3 нь бодит, ажиллагаатай API юм. Гэхдээ хязгаартай.
Хэрэглэгчийн нэвтрэлт байхгүй. Бүх хүн нэг API key хуваалцдаг. "Энэ бол миний тэмдэглэл, тэр бол таных" гэсэн ойлголт байхгүй. Жинхэнэ auth нь Бүлэг 15-т нэрлэгдэх цаашдын зам.
Migration байхгүй. Model өөрчлөхөд .db устгах ёстой. Production-д энэ нь боломжгүй — Alembic хэрэгтэй.
SQLite-ийн хязгаар. Нэг сервер, хязгаарлагдмал зэрэг бичилт (Бүлэг 10-ын Хичээл 2).
Тест байхгүй. Кодыг автоматаар шалгах систем байхгүй.
Deployment байхгүй. API зөвхөн таны компьютер дээр ажиллана.
Эдгээрийг Бүлэг 15-т бүгдийг нэрлэж, чиглэл өгнө. Одоохондоо тэднийг мэдэж байх нь чухал: та бүрэн систем бүтээгээгүй, гэхдээ бодит суурь бүтээсэн.
v3 = v2-ийн бүтэц + жинхэнэ өгөгдлийн сан. Хамгаалалт, тохиргоо, алдааны handler бүгд хэвээр.
Шинэ файл: database.py — engine, create_db_and_tables, get_session нэг газар.
DATABASE_URL нь .env-д — PostgreSQL руу шилжих зам нээлттэй, нууц кодоос гадна.
Model-ууд BaseModel -> SQLModel; Note нь table=True авсан.
errors.py болон dependencies.py бараг өөрчлөгдөөгүй — сайн бүтцийн ашиг: өөрчлөлт нэг газарт хязгаарлагдана.
find_note нь одоо session хүлээж авдаг, гэхдээ логик нь ижил: ол, олдохгүй бол 404.
Хайлт [n for n in ...] -> .where(); хуудаслалт slicing -> .offset().limit().
startup event-д create_db_and_tables() — давтагдахад аюулгүй.
Байнгын байдал батлагдлаа: сервер унтарч асахад өгөгдөл газраасаа хөдлөөгүй.
Үлдсэн хязгаар: хэрэглэгчийн нэвтрэлт, migration, тест, deployment — Бүлэг 15-т нэрлэгдэнэ.
Түвшин 4 дууслаа. Тэмдэглэлийн API-ийн гурван хувилбарын аян дуусав: v1 (санах ойд), v2 (мэргэжлийн бүтэц), v3 (өгөгдлийн сан). Ижил программ, гурван удаа, тавьсан суурин дээрээ өссөн.
Түвшин 5-д бид гурван нэмэлт чадвар сурна (Бүлэг 13): FastAPI дотор async хэзээ хэрэгтэй, CORS гэж юу болох, pagination-ыг зөв хийх. Дараа нь capstone — Номын сангийн API (Бүлэг 14), Курс 2-ын номын сангийн систем жинхэнэ вэб үйлчилгээ болж дахин төрнө. Эцэст нь Бүлэг 15-д бид deployment-ыг ойлголтын түвшинд авч үзэж, цаашдын замыг зурж, гурван сургалтын аяныг дүгнэнэ.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.