Ачааллж байна...
Өмнөх хичээлд бид кодоо олон файлд задалсан: main.py, notes.py, users.py. Гэхдээ файлуудыг зүгээр л хажуу хажууд нь, нэг хавтаст тавьсан. Хэдэн файл байхад энэ нь зүгээр. Гэхдээ жинхэнэ төсөл өсөхөд файлууд олширч, тэдгээрийг зөвхөн хажуу хажууд нь тавих нь замбараагүй болдог.
Бодит төсөл файлаа хавтсаар зохион байгуулдаг: router-ууд нэг хавтаст, model-ууд өөр хавтаст, тохиргоо гурав дахь газар. Энэ хичээлд бид тэр бүтцийг сурч, Тэмдэглэлийн API-г мэргэжлийн бүтэц рүү шилжүүлнэ. Курс 2-ын Бүлэг 12-ын package мэдлэг энд бүрэн ажиллана.
Курс 2-ын Бүлэг 12-т та package сурсан. Богино сануулга: package бол Python файлуудыг агуулсан хавтас юм. Хавтас доторх файлуудыг цэгээр import хийдэг:
python
from myfolder.helpers import greetЭнэ нь "myfolder хавтас доторх helpers.py файлаас greet-ыг ав" гэсэн үг. Хавтас нь код бүлэглэх дараагийн түвшин — файл функцийг бүлэглэдэг бол хавтас файлыг бүлэглэдэг.
Түүхэн шалтгаанаар package хавтаст __init__.py гэсэн хоосон файл хэрэгтэй байсан. Орчин үеийн Python-д энэ нь ихэвчлэн шаардлагагүй, гэхдээ зарим тохиолдолд хэрэг болдог тул бид түүнийг оруулна — доор тайлбарлана.
Эхлээд зорих бүтцээ харъя. Бид дараах хавтас, файлын бүтцийг үүсгэнэ:
fastapi-course/
├── venv/ (виртуал орчин — гар хүрэхгүй)
├── main.py (app үүсгэх, router холбох — цөөн мөр)
└── app/ (бүх бодит код энд)
├── __init__.py (хоосон — app-ыг package болгоно)
├── models.py (бүх Pydantic model)
└── routers/ (router бүр өөрийн файлд)
├── __init__.py (хоосон)
├── notes.py
└── users.pyГурван түвшний зохион байгуулалт байна.
Хамгийн гадна main.py — програмын эхлэл цэг. Зөвхөн app үүсгэж, router-уудыг холбоно. Богино, тогтвортой.
app/ хавтас — бүх бодит код энд. Логик, model, endpoint. main.py-г цэвэрхэн байлгахын тулд бүх зүйлийг энд төвлөрүүлдэг.
app/routers/ хавтас — router бүр өөрийн файлд. Нэг нөөц = нэг файл гэсэн дүрэм (өмнөх хичээлээс) энд хавтас болж хэлбэржиж байна.
"Яагаад ингэж хутгах вэ? Бүх зүйл нэг хавтаст байхад болохгүй гэж үү?" гэсэн асуулт гарч болно. Гурван шалтгаан бий.
Нэгд, олдоц. Router хайж байвал routers/ хавтсыг нээнэ. Model хайж байвал models.py-г нээнэ. Юу хаана байгаа нь бүтцээс шууд ойлгогдоно. Хэдэн зуун файлтай төсөлд энэ нь асар их цаг хэмнэдэг.
Хоёрт, тусгаарлал. Тэмдэглэл дээр ажиллах хүн routers/notes.py-г л нээнэ; бусад файлд гар хүрэхгүй. Хэд хэдэн хүн зэрэг ажиллахад мөргөлдөх магадлал багасна.
Гуравт, өсөлт. Төсөл өсөхөд шинэ router нэмэхэд зөвхөн routers/ хавтаст шинэ файл нэмнэ. Бүтэц нь өсөлтийг даана. Нэг файлын бүтэц 500 мөрөнд задардаг; хавтасны бүтэц мянган файлыг ч дааж чадна.
VS Code-ийн зүүн талын файлын жагсаалт дээр ажиллана.
Эхлээд app хавтас үүсгэнэ. Файлын жагсаалт дээр хоосон газар баруун товшоод New Folder, нэрийг app гэнэ.
app доторх routers хавтас үүсгэнэ. app дээр баруун товшоод New Folder, нэрийг routers гэнэ.
Одоо бүтэц ийм байна:
fastapi-course/
├── venv/
├── main.py
└── app/
└── routers/(Windows дээр PowerShell-ээр хийхийг хүсвэл: mkdir app, mkdir app\routers. Гэхдээ VS Code-ийн файлын жагсаалт дээр хийх нь илүү энгийн — Курс 2-т сурсанчлан PowerShell дээр зам бичихэд алдаа гардаг.)
app болон app/routers хавтас тус бүрд __init__.py гэсэн хоосон файл үүсгэнэ.
app дээр баруун товшоод New File, нэрийг __init__.py гэнэ. Дотор нь юу ч бичихгүй — хоосон үлдээнэ.
app/routers дээр мөн адил __init__.py үүсгэнэ. Мөн хоосон.
Одоо бүтэц:
fastapi-course/
├── venv/
├── main.py
└── app/
├── __init__.py
└── routers/
└── __init__.pyЯагаад хоосон файл вэ
__init__.py нь хачирхалтай санагдаж болно — хоосон файл юунд хэрэгтэй вэ? Түүний оршихуй нь Python-д "энэ хавтас бол package, доторх файлуудыг import хийж болно" гэж хэлдэг. Хоосон ч гэсэн энэ дохио чухал.
Орчин үеийн Python (3.3-аас хойш) __init__.py-гүйгээр ч import хийж чаддаг зарим тохиолдол бий. Гэхдээ түүнийг оруулах нь илүү найдвартай, олон хэрэгсэл (жишээ нь тест) түүнийг хүлээдэг тул бид үргэлж оруулна. Хоосон __init__.py нэмэх нь хэзээ ч буруу биш.
Бүх Pydantic model-ыг нэг газар төвлөрүүлье. 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 UserCreate(BaseModel):
name: str
email: str
class UserPublic(BaseModel):
id: int
name: str
email: strХадгална.
Яагаад model-уудыг тусад нь
Model-уудыг өөрийн файлд төвлөрүүлэх нь хэд хэдэн ашигтай. Model-ыг хэд хэдэн router ашиглаж болно — жишээ нь NotePublic-ыг notes router болон статистик router хоёулаа. Хэрэв model нь тодорхой нэг router файлд байсан бол давхардал үүсэх байсан. Тусад нь байвал бүх router нэг эх сурвалжаас import хийдэг.
Мөн model-уудыг нэг дор харах нь таны өгөгдлийн бүтцийг нэг дор ойлгоход тусална — API-ийн "хэлбэр" бүхэлдээ нэг файлд.
app/routers хавтаст notes.py үүсгэнэ:
python
# app/routers/notes.py
from fastapi import APIRouter, HTTPException
from app.models import NoteCreate, NotePublic
router = APIRouter(prefix="/notes", tags=["Тэмдэглэл"])
notes: list[dict] = []
next_id = 1
@router.get("", response_model=list[NotePublic])
def get_notes():
return notes
@router.post("", status_code=201, response_model=NotePublic)
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.get("/{note_id}", response_model=NotePublic)
def get_note(note_id: int):
for note in notes:
if note["id"] == note_id:
return note
raise HTTPException(status_code=404, detail="Тэмдэглэл олдсонгүй")Хадгална.
Кодын задаргаа
from app.models import NoteCreate, NotePublic — энэ бол гол шинэ зүйл. Хавтас доторх файлаас import хийж байна. app.models гэдэг нь "app хавтас доторх models.py" гэсэн үг. Курс 2-ын Бүлэг 12-ын package import яг ажиллаж байна.
Цэг (app.models) нь хавтасны шатлалыг заана. Хэрэв model нь илүү гүн байсан бол (app.schemas.notes) илүү олон цэг байх байсан.
tags=["Тэмдэглэл"] — шинэ параметр. Энэ нь /docs хуудсан дээр endpoint-уудыг бүлэглэдэг. Бид түүнийг дараагийн хичээлд дэлгэрэнгүй үзнэ; одоохондоо энэ нь баримт бичгийг цэгцэлдэг гэдгийг мэдэж байхад хангалттай.
Model-ууд одоо энэ файлд зарлагдаагүй — тэдгээр нь models.py-д байгаа, эндээс import хийгдэж байна. Файл богиносч, зөвхөн endpoint-ийн логик үлдсэн.
app/routers хавтаст users.py үүсгэнэ:
python
# app/routers/users.py
from fastapi import APIRouter
from app.models import UserCreate, UserPublic
router = APIRouter(prefix="/users", tags=["Хэрэглэгч"])
users: list[dict] = []
next_id = 1
@router.get("", response_model=list[UserPublic])
def get_users():
return users
@router.post("", status_code=201, response_model=UserPublic)
def create_user(user: UserCreate):
global next_id
new_user = user.model_dump()
new_user["id"] = next_id
users.append(new_user)
next_id += 1
return new_userХадгална.
Ижил загвар: model-уудыг app.models-аас import, өөрийн prefix болон tag.
Одоо main.py-г бүхэлд нь солино:
python
# main.py
from fastapi import FastAPI
from app.routers import notes, users
app = FastAPI(title="Тэмдэглэлийн API")
app.include_router(notes.router)
app.include_router(users.router)Хадгална.
Кодын задаргаа
from app.routers import notes, users — app/routers хавтаснаас хоёр модулийг import хийж байна. Энэ бол хавтас доторх хавтас доторх файл — гурван түвшний гүн, гэхдээ цэгээр цэгцтэй.
app.include_router(notes.router) — өмнөх хичээлээс танил. notes бол одоо app.routers.notes модуль, түүний доторх router-ыг холбож байна.
main.py тав хүрэхгүй мөр. Бүх логик app/ дор цэгцтэй байна. Энэ бол мэргэжлийн FastAPI төслийн эхлэл цэг хэрхэн харагддаг жишээ.
Энд чухал зүйл байна. Одоо серверийг хаанаас ажиллуулах вэ?
Терминал дээр төслийн үндсэн хавтаст (fastapi-course/, app/ дотор биш) байгаа эсэхээ шалгаад:
fastapi dev main.pymain.py нь үндсэн хавтаст байгаа тул энэ тушаал ажиллана. FastAPI main.py-г ажиллуулж, тэр нь app/ хавтаснаас import хийж, бүх зүйл холбогдоно.
Туршина
http://127.0.0.1:8000/docs/docs хуудсан дээр endpoint-ууд одоо бүлэглэгдсэн харагдана:
Тэмдэглэл
GET /notes
POST /notes
GET /notes/{note_id}
Хэрэглэгч
GET /users
POST /userstags параметр endpoint-уудыг гарчгаар нь бүлэглэсэн. Кодын бүтэц (хоёр router файл) баримт бичгийн бүтэц (хоёр бүлэг) болж тусгагдсан.
http://127.0.0.1:8000/notesХариу: []. Ажиллаж байна. Код гурван түвшинд тархсан ч API яг адилхан ажиллаж байна.
Нэг чухал зүйлийг тодруулъя, учир нь энэ нь эндүүрэл үүсгэдэг.
from app.models import ... гэсэн зам үндсэн хавтаснаас эхэлдэг — тэр газраас та серверээ ажиллуулж байгаа. app.models гэдэг нь "энэ програмыг ажиллуулж байгаа хавтас доторх app хавтас доторх models.py" гэсэн үг.
Тиймээс серверээ үргэлж үндсэн хавтаснаас ажиллуулах ёстой. Хэрэв та app/ хавтас руу орж, тэндээс ажиллуулбал import-ууд эвдэрнэ — учир нь app хавтас доторх байрлалаас app.models гэсэн зам олдохгүй.
Дүрэм: серверийг үргэлж төслийн үндсэн хавтаснаас ажиллуул. fastapi-course/ дотор бай, fastapi-course/app/ дотор биш.
app/ дотроос ажиллуулах
Терминал app/ хавтаст байхад fastapi dev main.py гэвэл — эхлээд main.py олдохгүй (app/ дотор main.py байхгүй). Хэрэв та app/ доторх файлыг ажиллуулах гэвэл import-ууд эвдэрнэ:
ModuleNotFoundError: No module named 'app'Засвар: үндсэн хавтас руу буц (cd ..), тэндээс ажиллуул.
import-ийн зам буруу
python
from models import NoteCreate # буруу — app. дутуу
from app.models import NoteCreate # зөвfrom models import ... нь "энэ хавтаст models.py байна" гэж хайна, гэхдээ models.py нь app/ дотор. Бүтэн зам (app.models) хэрэгтэй.
Гаралт:
ModuleNotFoundError: No module named 'models'init.py мартах
Хэрэв app/__init__.py эсвэл app/routers/__init__.py байхгүй бол зарим тохиолдолд import ажиллахгүй байж болно:
ModuleNotFoundError: No module named 'app'Хэдийгээр орчин үеийн Python заримдаа __init__.py-гүйгээр ажилладаг ч, түүнийг оруулах нь найдвартай. Хоосон __init__.py хоёр хавтаст байгаа эсэхийг шалгаарай.
Цикл import
Хэрэв models.py нь routers/notes.py-аас import хийж, notes.py нь models.py-аас import хийвэл — цикл үүснэ, хоёул бие биенээ хүлээж эргэлдэнэ:
ImportError: cannot import name ... (most likely due to a circular import)Үүнээс зайлсхийх дүрэм: import нэг чиглэлд урсах ёстой. Router-ууд model-аас import хийдэг, model-ууд router-аас хийдэггүй. Model нь суурь давхарга, router нь дээд давхарга. Дээд нь доодоос авдаг, эсрэгээр биш.
Шударга зөвлөгөө: энэ бүтэц ганц зөв хариу биш. FastAPI ямар бүтэц шаарддаггүй — та файлаа хүссэнээрээ зохион байгуулж болно. Зарим төсөл models.py биш schemas/ хавтас ашигладаг. Зарим нь router бүрд model-оо хамт байлгадаг. Зарим нь илүү олон түвшин ашигладаг.
Гэхдээ дээрх бүтэц бол түгээмэл, ойлгомжтой, өсдөг загвар. FastAPI-ийн албан ёсны баримт бичиг ч үүнтэй төстэй бүтэц санал болгодог. Тиймээс бид түүнийг ашиглана — та бодит төсөлд ийм бүтэцтэй байнга тааралдана.
Гол зарчим нь бүтцийн нэр биш, харин: төстэй зүйлийг хамт байлга, ялгаатай зүйлийг тусгаарла, import нэг чиглэлд урсга. Энэ зарчмыг баримталсан бол бүтцийн нарийн ширийн чөлөөтэй.
Хүсвэл гурав дахь router нэмж үзээрэй — жишээ нь app/routers/tags.py, models.py-д Tag model нэмээд. main.py-д гурав дахь include_router нэмж, /docs дээр гурван бүлэг гарахыг ажиглаарай. Шинэ нөөц нэмэхэд бүтэц хэрхэн даахыг гар дээрээ мэдрэх нь энэ хичээлийн санааг бататгана.
Сонирхвол серверээ санаатайгаар app/ хавтас дотроос ажиллуулаад, гарах ModuleNotFoundError-ыг хараарай. Дараа нь буцаж үндсэн хавтаснаас ажиллуулна. import-ийн зам хаанаас эхэлдгийг гар дээрээ мэдрэх нь чухал.
Бодит төсөл файлаа хавтсаар зохион байгуулна: main.py (эхлэл), app/ (код), app/routers/ (router бүр өөрийн файлд).
__init__.py (хоосон) нь хавтсыг package болгоно — бид үргэлж оруулна.
models.py нь бүх Pydantic model-ыг төвлөрүүлнэ — router-ууд эндээс import хийнэ.
Хавтас доторх import: from app.models import NoteCreate (цэгээр шатлал).
main.py нь from app.routers import notes, users -> include_router. Цөөн мөр.
Серверийг үргэлж төслийн үндсэн хавтаснаас ажиллуул (import-ийн зам тэндээс эхэлдэг).
import нэг чиглэлд урсана: router -> model, эсрэгээр биш (цикл import-аас зайлсхий).
Бүтэц заавал биш, гэхдээ зарчим чухал: төстэйг хамт, ялгаатайг тусад, import нэг чиглэлд.
Одоо та мэргэжлийн бүтэцтэй, олон файлт, олон router-тай төсөл зохион байгуулж чадна. Өмнөх хичээлд бид tags параметрийг товч дурдаад өнгөрсөн — тэр нь /docs хуудсыг бүлэглэдэг байсан. Дараагийн хичээл богино бөгөөд түүнд бүрэн зориулагдана: бид tags ашиглан баримт бичгээ хэрхэн цэгцлэх, олон endpoint-той API-ийн /docs хуудсыг хэрхэн уншихад хялбар болгохыг үзнэ. Тэр нь Бүлэг 7-г төгсгөж, бид Depends руу орох болно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.