Fast API&MySQL
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
# 1. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ง ์์ฑ
DATABASE_URL = "mysql+pymysql://user:password@localhost:3306/db_name"
engine = create_engine(DATABASE_URL)
# 2. ๋ฒ ์ด์ค ํด๋์ค ์์ฑ
Base = declarative_base()
# 3. ๋ชจ๋ธ ์ ์ (DB ํ
์ด๋ธ ๋งคํ)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
email = Column(String(100))
# 4. ํ
์ด๋ธ ์์ฑ
Base.metadata.create_all(bind=engine)
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
- DATABASE_URL: MySQL ์ฐ๊ฒฐ ์ ๋ณด (์ฌ์ฉ์: user, ๋น๋ฐ๋ฒํธ: password, DB: db_name)
- mysql+pymysql: SQLAlchemy์๊ฒ MySQL์ ์ฌ์ฉํ๊ณ , ํต์ ์ pymysql ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํจ์ ์๋ฆผ
- engine: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ง ์์ฑ
- Base: ORM ๋ชจ๋ธ ๋ฒ ์ด์ค ํด๋์ค, declarative_base()=๋ชจ๋ ๋ชจ๋ธ์ด ์์๋ฐ์์ผํ๋ ๊ธฐ๋ณธ ํด๋์ค
ํ ์ด๋ธ ์๋ ์์ฑ
- ์ ์๋ ๋ชจ๋ธ ๊ธฐ๋ฐ์ผ๋ก DB ํ ์ด๋ธ ์๋ ์์ฑ
- SQLAlchemy์ ๋ชจ๋ธ ํด๋์ค๋ฅผ ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ๋ก ๋ณํ
- ํ ์ด๋ธ์ด ์ด๋ฏธ ์กด์ฌ ์ ๋ฌด์ํจ. ๊ฐ๋ฐ์ ์ฌ์ฉ
์ธ์
from sqlalchemy.orm import sessionmaker
# ์ธ์
ํฉํ ๋ฆฌ ์์ฑ
SessionLocal = sessionmaker(
autocommit=False, # ์๋ ์ปค๋ฐ ๋นํ์ฑํ
autoflush=False, # ์๋ ํ๋ฌ์ ๋นํ์ฑํ
bind=engine
)
# ์์กด์ฑ ์ฃผ์
์ ์ํ ์ธ์
๊ด๋ฆฌ ํจ์
def get_db():
db = SessionLocal()
try:
yield db # ์์ฒญ ์ฒ๋ฆฌ ๋์ ์ธ์
์ฌ์ฉ
finally:
db.close() # ์์ฒญ ์ข
๋ฃ ์ ์ธ์
๋ฐํ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์ ๊ด๋ฆฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ด๋ ค๋ฉด "์ธ์ "์ด ํ์ํ๋ค.
- ์ธ์ ์ ์ผ์ข ์ ์ฐ๊ฒฐ ํต๋ก๋ก, ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ด๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊ณ , ๋ณ๊ฒฝ์ฌํญ์ ์ปค๋ฐํ๊ฑฐ๋ ๋กค๋ฐฑํ๋ ์ญํ
- SQLAlchemy์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ํธ์์ฉ์ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด. ๋ฐ๋ผ์, CRUD๋ฅผ ์ํด์๋ ์ธ์ ์ด ํ์ํ๋ค.
- 2๊ฐ์ง ๋ฐฉ์์ด ์กด์ฌํ๋ค. (Depends, sessionMaker)
Depends
FastAPI์ Depends ๊ธฐ๋ฅ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด, ๊ฐ ์์ฒญ๋ง๋ค ์ธ์
์ ์๋์ผ๋ก ์ด๊ณ , ์์ฒญ์ด ๋๋๋ฉด ์๋์ผ๋ก ๋ซ์์ค๋ค.
์์กด์ฑ ์ฃผ์
์ ํตํ DB ์ธ์
๊ด๋ฆฌ
์์ฒญ ์๋ฃ ์ ์ธ์ ์๋ ์ข ๋ฃ
db = Session(bind=engine): ์ ์ธ์
(์ฐ๊ฒฐ)์ ์์ฑ
try:
yield db: ์ด ์ธ์
์ FastAPI ์๋ํฌ์ธํธ ํจ์์ ์ ๋ฌ
finally:
db.close(): ์์ฒญ์ด ๋๋๋ฉด(์ ์/์๋ฌ ๋ชจ๋) ์ธ์
์ ๋ซ์ ๋ฆฌ์์ค ๋์๋ฅผ ๋ฐฉ์ง
ํ์ด์ฌ์์ yield๋ ํจ์ ๋ด์์ ์ฌ์ฉ๋๋ฉด ๊ทธ ํจ์๋ฅผ "์ ๋๋ ์ดํฐ ํจ์"๋ก ๋ง๋ค์ด์ฃผ๋ ํค์๋
์ผ๋ฐ์ ์ผ๋ก ํจ์์์ return์ ์ฌ์ฉํ๋ฉด ๊ฐ์ ํ ๋ฒ๋ง ๋ฐํํ๊ณ ํจ์๊ฐ ๋๋์ง๋ง, yield๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ ํ๋ ๋ฐํํ ๋ค ํจ์ ์คํ์ด ๋ฉ์ถ๊ณ , ๋ค์์ ๋ค์ ํธ์ถ๋๋ฉด ๊ทธ ๋ค์ ์ค๋ถํฐ ์คํ์ ์ด์ด๊ฐ๋ค.
์ฆ, yield๋ ๊ฐ์ "ํ๋์ฉ" ๋ฐํํ๋ฉด์ ํจ์ ์คํ์ ์ ์ ๋ฉ์ท๋ค๊ฐ, ๋ค์์ ๋ ์คํ๋๋ฉด ๋ฉ์ท๋ ๋ถ๋ถ๋ถํฐ ์ด์ด์ ์คํํ ์ ์๊ฒ ํด์ค๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ํจ์(์ ๋๋ ์ดํฐ ํจ์)๋ ๋ฐ๋ณต์(iterator)์ฒ๋ผ ๋์ํ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋ผ๋ฉด์ ์์ฐจ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
FastAPI์์ get_db() ํจ์์ yield๋ฅผ ์ฐ๋ ์ด์ ๋ ์๋ํฌ์ธํธ ํจ์๊ฐ DB ์ธ์
์ ์ฌ์ฉํ ์ ์๊ฒ ์ ๋ฌํด์ฃผ๊ณ , ์์ฒญ ์ฒ๋ฆฌ๊ฐ ๋๋๋ฉด finally ๋ธ๋ก์์ ์ธ์
์ ์์ ํ๊ฒ ๋ซ์ ์ ์๊ฒ ํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
์ฆ, yield๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ชฝ ์ฝ๋๋ "์ธ์
์ ์ด์ด์ ์๋ํฌ์ธํธ์ ์ ๋ฌ"ํ๋ ์ญํ , yield ๋ค์ชฝ finally ์ฝ๋๋ "์์ฒญ์ด ๋๋๋ฉด ์ธ์
์ ๋ซ๋ ์ ๋ฆฌ ์์
"์ ๋ด๋น
Pydantic ๋ชจ๋ธ
# MemoCreate: ๋ฉ๋ชจ ์์ฑ์ฉ ํ์ ํ๋. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ฉ๋ชจ๋ฅผ ๋ง๋ค ๋ ๋ ํ๋๋ฅผ ๋ฐ๋์ ๋ณด๋ด์ผ ํ๋ฉฐ, ํ์
์ด ๋ค๋ฅด๊ฑฐ๋ ๋๋ฝ๋๋ฉด ์๋์ผ๋ก ์๋ฌ๋ฅผ ๋ฐํ
# MemoUpdate: ๋ฉ๋ชจ ์์ ์ฉ ์ ํ์ ํ๋. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ ์ค ํ๋๋ง ๋ณด๋ด๋ ๋๊ณ , ๋ ๋ค ๋ณด๋ด๋ ๋๊ณ , ์๋ฌด๊ฒ๋ ์ ๋ณด๋ด๋ฉด ์๋ฌด ๋ณํ๋ ์๋ค. -> PATCH
class MemoCreate(BaseModel):
title: str
content: str
class MemoUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
Pydantic์ BaseModel์ ์์๋ฐ์ ๋ง๋ ํด๋์ค๋ "๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ"์ "์๋ ๋ฌธ์ํ"๋ฅผ ๋ด๋นํ๋ค.
FastAPI๋ API ์์ฒญ์ ๋ฐ์ ๋, body์ ๋ด๊ธด JSON ๋ฐ์ดํฐ๋ฅผ ์ด BaseModel๋ก ๋ณํํ๊ณ , ํ์ ๊ณผ ํ์/์ ํ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํ๋ค.
์ ํ์ํ๊ฐ?
- ๋ณด์: ์๋ชป๋ ๋ฐ์ดํฐ๊ฐ DB์ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ง์
- ์๋ ๋ฌธ์ํ: API ๋ฌธ์(Swagger ๋ฑ)์ ์๋ ๋ฐ์
- ์ฝ๋ ๊ฐ๊ฒฐํ: ๋ฐ์ดํฐ ๊ฒ์ฆ ๋ก์ง์ ์ผ์ผ์ด ์์ฑํ ํ์ ์๋ค.
์์กด์ฑ ์ฃผ์ ์ค์
ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ UserSchema๋ชจ๋ธ๋ก ๋ฐ๋๋ก ์ค์ , Depends(get_db)๋ ๋งค๊ฐ๋ณ์๋ก ์ ์ํ ์์กด์ฑ ํจ์ get_dbํจ์๋ช ์ ๋ฃ์. ํด๋น ํจ์์ ๋ฐํ๊ฐ์ด Session ๊ฐ์ฒด์ด๋ฏ๋ก, ํ์ ์ Session์ผ๋ก ์์ฑ๊ฐ๋ฅ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ฒด ์์ฑ: new_user=User(): User ๋ชจ๋ธ ์ธ์คํด์ค ์์ฑ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์ ์ ๊ฐ์ฒด ์ถ๊ฐ: db.add(new_user): ์์ฑ๋ User์ธ์คํด์ค๋ฅผ ํ์ฌ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์ ์ ์ถ๊ฐ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ปค๋ฐ: db.commit(): ํ ์ด๋ธ ๊ฐ์ฒด ๋ด์ฉ์ ๋ณ๊ฒฝํ๋ฉด db.commit()ํธ์ถํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์ ์ ๋ํ ๋ณ๊ฒฝ์ฌํญ์ DB์ ๋ฐ์
- ๊ฐ์ฒด์ ๋ณด ๊ฐฑ์ : db.refresh(new_user): db.refresh()๋ฅผ ํธ์ถํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ปค๋ฐ๋ ์๋ก์ด user์ธ์คํด์ค์ ์ ๋ณด๋ฅผ ์ต์ ์ํ๋ก ๊ฐฑ์
- commit์ ํ์ด์ฌ์์ ๋ณ๊ฒฝํ ๋ด์ฉ์ DB์ ์ ์ฅํ๋ ๋์. ์ฆ, ํ์ด์ฌ → DB
- refresh๋ DB์ ์ด๋ฏธ ์ ์ฅ๋(์ปค๋ฐ๋) ๊ฐ์ DB์์ ํ์ด์ฌ ๊ฐ์ฒด๋ก ๋ค์ ์ฝ์ด์ค๋ ๋์. ์ฆ, DB → ํ์ด์ฌ
์ด๋ฅผํตํด ๊ฐ ์์ฒญ์ ๋ผ์ดํ์ฌ์ดํด ๋์ DB ์ธ์ ์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌ. Pydantic๋ชจ๋ธ ์ฌ์ฉํ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฆ๊ณผ SQLAlchemey๋ชจ๋ธ์ ํตํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ํ ๊ฐ๋ฅ
Dependsํตํด ์ฃผ์ ๋ get_db()ํจ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ ์งํ๊ณ , ๋ชจ๋ ์ฒ๋ฆฌ ์๋ฃ ํ ํด๋น ์ฐ๊ฒฐ ์ข ๋ฃ
CRUD
from fastapi import Depends
# Create
@app.post("/users")
def create_user(user_data: UserSchema, db: Session = Depends(get_db)):
new_user = User(name=user_data.name, email=user_data.email)
db.add(new_user)
db.commit() # ๋ณ๊ฒฝ์ฌํญ ์ ์ฅ
db.refresh(new_user) # DB์์ ์๋ก๊ณ ์นจ
return new_user
# Read
@app.get("/users/{user_id}")
def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
return user
# Update
@app.put("/users/{user_id}")
def update_user(user_id: int, update_data: UserUpdate, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
user.name = update_data.name
db.commit()
db.refresh(user)
return user
# Delete
@app.delete("/users/{user_id}")
def delete_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
db.delete(user)
db.commit()
return {"message": "User deleted"}
1. ๋ฉ๋ชจ ์์ฑ (POST)
๋์: ์ ๋ฉ๋ชจ ์์ฑ → DB ์ ์ฅ → ์์ฑ๋ ๊ฐ์ฒด ๋ฐํ
๋ฐํ๊ฐ: ์์ฑ๋ ๋ฉ๋ชจ์ ID, ์ ๋ชฉ, ๋ด์ฉ
db: Depends(get_db)๋ก DB ์ธ์ ์ด ์๋ ์ฃผ์
์ญํ : ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํต์ ํ ์ ์๋ ์ธ์ ๊ฐ์ฒด
์ด๋ป๊ฒ ์ฑ์์ง๋?
Depends(get_db)๋ FastAPI์ ์์กด์ฑ ์ฃผ์ ๊ธฐ๋ฅ
FastAPI๊ฐ get_db() ํจ์๋ฅผ ์คํํด์, ๋ฐํ๋ db ์ธ์ ์ ์ด ํ๋ผ๋ฏธํฐ์ ์๋์ผ๋ก ๋ฃ์ด์ค๋ค.
db.commit(): ์ค์ ๋ก DB์ ์ ์ฅ
db.refresh(new_memo): DB์์ ์๋ก ์์ฑ๋ ๋ฉ๋ชจ์ ์ ๋ณด๋ฅผ ๋ค์ ์ฝ์ด์ด(์: id)
'''
5. Pydantic ์คํค๋ง
์ญํ ๊ณผ ํ์์ฑ
Pydantic์ BaseModel์ ์์๋ฐ์ ๋ง๋ ํด๋์ค๋ "๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ"์ "์๋ ๋ฌธ์ํ"๋ฅผ ๋ด๋นํฉ๋๋ค.
FastAPI๋ API ์์ฒญ์ ๋ฐ์ ๋, body์ ๋ด๊ธด JSON ๋ฐ์ดํฐ๋ฅผ ์ด BaseModel๋ก ๋ณํํ๊ณ , ํ์
๊ณผ ํ์/์ ํ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํฉ๋๋ค.
์ ํ์ํ๊ฐ?
๋ณด์: ์๋ชป๋ ๋ฐ์ดํฐ๊ฐ DB์ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ง์
์๋ ๋ฌธ์ํ: API ๋ฌธ์(Swagger ๋ฑ)์ ์๋ ๋ฐ์
์ฝ๋ ๊ฐ๊ฒฐํ: ๋ฐ์ดํฐ ๊ฒ์ฆ ๋ก์ง์ ์ผ์ผ์ด ์์ฑํ ํ์ ์์
MemoCreate: ๋ฉ๋ชจ ์์ฑ์ฉ ํ์ ํ๋. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ฉ๋ชจ๋ฅผ ๋ง๋ค ๋ ๋ ํ๋๋ฅผ ๋ฐ๋์ ๋ณด๋ด์ผ ํ๋ฉฐ, ํ์
์ด ๋ค๋ฅด๊ฑฐ๋ ๋๋ฝ๋๋ฉด ์๋์ผ๋ก ์๋ฌ๋ฅผ ๋ฐํ
MemoUpdate: ๋ฉ๋ชจ ์์ ์ฉ ์ ํ์ ํ๋. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ ์ค ํ๋๋ง ๋ณด๋ด๋ ๋๊ณ , ๋ ๋ค ๋ณด๋ด๋ ๋๊ณ , ์๋ฌด๊ฒ๋ ์ ๋ณด๋ด๋ฉด ์๋ฌด ๋ณํ๋ ์๋ค. -> PATCH
'''
'๐ผ ๋ฐฑ์ค๋ > Fast API' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Fast API - ๋ชจ๋ธ ์๋น (2) | 2025.06.25 |
---|---|
Fast API - ์ฑ๋ฅ ๊ฐ์ (0) | 2025.06.23 |
Fast API - ๊ธฐ๋ฅ (3) | 2025.06.23 |
Fast API - ๊ธฐ์ด (3) | 2025.06.18 |