Python/Backend

FastAPI에서 sqlalchemy 활용 SQL DB CRUD 구현 예제

jimmy_AI 2024. 5. 23. 00:34
반응형

안녕하세요. 아래 링크의 지난 글에서는 NoSQL인 MongoDB를 기준으로

fastapi의 CRUD 메소드 구현 방법을 알아보았습니다.

 

FastAPI에서 MongoDB 데이터 연동 CRUD 예제

안녕하세요. 아래 링크의 지난 글에서는 fastapi의 CRUD 메소드 사용 방법을 알아보았습니다. FastAPI get, post, patch, delete 예제 코드 정리파이썬의 대표 백엔드 모듈인 FastAPI에서 get, post, patch, delete 메

jimmy-ai.tistory.com

 

이어서 이번에는 관계형 데이터베이스(mysql, postgresql 등)를 기준으로

fastapi에서 CRUD 메소드들을 구현하는 방법을

마찬가지로 간략한 예제를 통해 정리해보도록 하겠습니다.

 

 

SQL 데이터베이스 불러오기 및 데이터 모델 정의

sqlalchemy 모듈에서 데이터베이스는 다음과 같은 코드를 통하여 불러올 수 있습니다.

# 모듈 설치 필요 시 pip install sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "사용할 DB의 url"

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

 

DB 객체를 가져오는 과정은 get_db() 함수를 통해서 수행되는데요.

여기서 generator로 구현된 이유는 DB 세션의 수명 주기를 요청 단위로 관리하기 위해서입니다.

이 접근 방식은 데이터베이스 세션을 효율적으로 생성, 사용하도록 도와주며,

요청이 끝나면 안전하게 종료할 수 있도록 해줍니다.

 

이번 예제에서 사용할 pydantic 데이터 모델은 다음과 같이 정해보도록 하겠습니다.

from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str
    email: str

    class Config:
        orm_mode = True

 

여기서 orm_mode = True로 설정한 이유는,

pydantic이 sqlalchemy 모델 객체를 받아들일 수 있게 하기 위해서입니다.

이 설정 덕분에, pydantic 모델이 sqlalchemy 데이터베이스 객체를 직접 사용할 수 있습니다.

 

데이터베이스 테이블을 객체 지향적으로 다루어

코드의 가독성, 유지보수성, 재사용성을 높이기 위해서

sqlalchemy 모델의 선언도 필요합니다. 이를 선언하는 예시 코드는 다음과 같습니다.

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = "users" # 실제 사용할 table 이름

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(256), nullable=False)
    email = Column(String(256), unique=True)

 

각 column의 특징들을 위의 예시처럼 적어주시면 됩니다.

 

 

get 메소드 예시

이제 CRUD 메소드 구현의 첫 번째로

id를 기준으로 해당하는 데이터를 조회하는 get 메소드 코드 예제를 살펴보겠습니다.

from fastapi import FastAPI, Depends, HTTPException

app = FastAPI()

@app.get("/users/{user_id}", response_model=User)
def read_user(user_id: int, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.id == user_id).first()
    if db_user is None: # 해당하는 id가 없는 경우 404 에러 반환
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

 

get_db 함수에 의존성 주입을 통하여 db 세션을 관리하고 있으며,

sqlalchemy 모델인 User 객체를 통하여 쿼리를 진행하고 있습니다.

 

 

post 메소드 예시

이번에는 새로운 데이터를 추가하는 post 메소드를 코드 예시를 살펴보겠습니다.

# id 값을 받지 않기에 id 속성이 없는 새로운 pydantic 모델 선언
class UserCreate(BaseModel):
    username: str
    email: str

@app.post("/users/", response_model=User)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    db_user = User(username=user.username, email=user.email)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

 

id 값은 input으로 받지 않고 새롭게 할당하는 과정을 위하여

id 속성이 포함되지 않은 UserCreate라는 pydantic 객체를 새롭게 선언하였으며,

add - commit - refresh의 세 단계를 거쳐 DB에 데이터를 추가하는 세션을

관리하고 있는 것을 확인해볼 수 있습니다.

 

 

patch 메소드 예시

저장된 데이터를 수정하는 patch 메소드의 코드 예시는 다음과 같습니다.

@app.patch("/users/{user_id}", response_model=User)
def update_user(user_id: int, user: UserCreate, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.id == user_id).first()
    if db_user is None: # 해당하는 id가 없는 경우 404 에러 반환
        raise HTTPException(status_code=404, detail="User not found")
    
    db_user.username = user.username
    db_user.email = user.email
    db.commit()
    db.refresh(db_user)
    return db_user

 

데이터를 조회하는 get 메소드의 예제에 해당하는 부분과

DB의 값을 업데이트하는 세션을 관리하는 post 메소드의 예제에 해당하는 부분이

적절하게 섞여서 작동하고 있는 점을 확인해볼 수 있습니다.

 

 

delete 메소드 예시

마지막으로 id를 기준으로 저장된 데이터를 지우는 delete 메소드 코드 예제입니다.

@app.delete("/users/{user_id}", response_model=User)
def delete_user(user_id: int, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.id == user_id).first()
    if db_user is None: # 해당하는 id가 없는 경우 404 에러 반환
        raise HTTPException(status_code=404, detail="User not found")
    
    db.delete(db_user)
    db.commit()
    return db_user

 

여기서도 데이터 조회 - 삭제 후 세션 관리의 단계로 나눠진 모습을 살펴볼 수 있습니다.

 

참고: 해당 코드 예제를 비동기 세션 처리(AsyncSession)로 진행하는 글이 업로드 되었습니다.

 

FastAPI 비동기 세션 처리 AsyncSession 활용 예제(sqlalchemy)

지난 번의 글에서는 FastAPI로 sqlalchemy 활용 CRUD 예제 코드를 다룬 적이 있습니다. FastAPI에서 sqlalchemy 활용 SQL DB CRUD 구현 예제안녕하세요. 아래 링크의 지난 글에서는 NoSQL인 MongoDB를 기준으로fastap

jimmy-ai.tistory.com

 

추가로, get, patch, delete에서 데이터를 조회하는 코드 부분이 유사한 만큼

해당 부분에 대한 리팩토링을 진행하면 도움이 될 수 있을 것입니다.