티스토리 뷰

728x90
반응형

목차

     

    FastAPI에서의 상속은 주로 SQLAlchemy 모델, Pydantic 모델, 그리고 라우터에 적용된다.

     

    한 줄 한 줄 더듬으며 개발하다 보니, 그리고 파이썬의 상속이 너무 간결하다 보니 그 기능을 오히려 잊게 될 때가 있는데,

     

    또다시 잊어버렸을 나중의 나를 위해서 굳이 글을 분리해서 정리한다.

     

    SQLAlchemy 모델의 상속

     

    SQLAlchemy는 ORM 라이브러리로, 디비 테이블을 파이썬 클래스로 표현한다.

     

    이때 'Base'라는 SQLAlchemy의 클래스를 상속받아 사용해야 하는데, 이는 나의 경우 db.py에 다음과 같이 선언되어 있다.

    Base: DeclarativeMeta = declarative_base()

    위와 같이 한 번만 선언하고 모든 모델에서 이 클래스를 상속받아 사용하게 되는데,

     

    그 이유는 하나의 Base객체가 전체 데이터베이스 스키마를 일관성 있게 관리할 수 있도록 하기 위함이다.

     

    또한 위에서 언급했듯이, 파이썬에서 클래스의 상속은 굉장히 간단하다.

    class Comment(Base):

    이런 식으로 클래스를 선언하는 것으로 상속이 끝난다.

     

    너무 간단해서 오히려 익숙해지는데 시간이 걸릴 정도였다.

     

    Base

     

    그렇다면 이 Base 클래스는 어떤 기능과 특성을 가지고 있을까.

     

    사실 기본적으로 추상 클래스인 Base에는 메서드나 데이터타입등이 명시적으로 정의되어 있지는 않다.

     

    데이터베이스 스키마에 따라 상속받은 뒤에 정의해서 사용할 수 있는데, 예를 들면 아래와 같은 것들이 있다.

     

    • 데이터 타입

      • Integer: 정수형 데이터
        String: 문자열 데이터 (길이 지정 가능)
        Text: 긴 문자열 데이터
        Float: 실수형 데이터
        Boolean: 참/거짓 값을 가질 수 있는 논리형 데이터
        DateTime: 날짜와 시간을 함께 저장
        Date: 날짜만 저장
        Time: 시간만 저장
        JSON: JSON 형태의 데이터
        Enum: 열거형 데이터 타입
    • 관계 설정

      • ForeignKey: 외래 키 설정
        relationship: ORM 레벨에서의 객체 관계 설정
        back_populates 또는 backref: 양방향 관계 설정
    • Column 설정

      • primary_key: 기본 키 설정
        index: 인덱스 설정
        unique: 고유 값 설정
        nullable: NULL 허용 설정
        default: 기본값 설정

    또한 Base는 위와 같은 모델 정의 이외에도 여러 기능을 함께 가지고 있는데, 역시 예를 들면 다음과 같다.

     

    • 유효성 검사: FastAPI는 자동으로 Base 모델의 스키마를 참조하여 요청과 응답의 유효성을 검사할 수 있다.
    • Dependency Injection: FastAPI의 의존성 주입 시스템을 사용하여, 각 API 요청에 대해 새로운 데이터베이스 세션을 생성하거나 기존 세션을 사용할 수 있다.
    • 자동 문서화: Base 모델을 사용하면, FastAPI는 자동으로 API 문서에 모델의 스키마 정보를 포함시킨다.
    • ORM을 이용한 비즈니스 로직: FastAPI에서는 Base와 연관된 SQLAlchemy 쿼리를 사용하여 비즈니스 로직을 구현할 수 있다.
    • 비동기 지원: FastAPI는 SQLAlchemy 1.4 이상을 지원하므로, asyncio와 함께 비동기 방식으로 데이터베이스를 사용할 수 있다.

    비즈니스 로직에 대해 조금 더 구체적으로 예를 들기 위해 코드를 가져오자.

    async def create_feed(
        db: Session, feed: FeedCreate, author_email: str, images: List[UploadFile] = None
    ):
        feed_dict = feed.model_dump()
        feed_dict["author_email"] = author_email
    
        if images:
            image_urls = upload_image_to_s3(images)
            feed_dict["image_urls"] = image_urls
    
        author = db.query(User).filter(User.email == author_email).first()
        if author is None:
            raise HTTPException(status_code=404, detail="Author Not Found")
    
        author_nickname = author.nickname
    
        db_feed = Feed(**feed_dict)
        db.add(db_feed)
        db.commit()
        db.refresh(db_feed)
    
        return {
            "id": db_feed.id,
            "title": db_feed.title,
            "content": db_feed.content,
            "author_email": db_feed.author_email,
            "author_nickname": author_nickname,
            "image_urls": db_feed.image_urls,
        }

    위 코드는 비동기적으로 피드를 생성하는 비즈니스 로직이다.

     

    SQLAlchemy를 상속받은 객체는 .query(), .add(), .commit()등을 자연스럽게 사용할 수 있으며

     

    이는 복잡한 디비 작업 없이도 RESTful API를 구성할 수 있어 생산성에 크게 도움이 된다.

     

    Pydantic 모델의 상속

     

    Pydantic은 지난 글에도 설명했듯이 파이썬의 데이터 유효성 검사 및 설정 관리 라이브러리이다.

     

    [FastAPI]FastAPI 튜토리얼

     

    [FastAPI]FastAPI 튜토리얼

    목차 지난 주말을 Flask와 MVC 패턴을 이용한 게시판 초기 설정에 갈아 넣었는데, 이번 월요일에 CTO님께서 FastAPI에 대한 언급을 하며 할 줄 알면 더 좋을 것 같다고 하셨다. 그간 파이썬 하면 장고

    gnidinger.tistory.com

    FastAPI의 Pydantic 모델은 바로 이 라이브러리의 BaseModel을 상속받아 생성되며,

    class FeedCreate(BaseModel):

    이를 통해 각 필드의 데이터 타입, 기본값을 비롯한 유효성 검사 조건을 지정할 수 있다.

     

    또한 Pydantic 모델에서 상속을 사용하면 부모 모델의 모든 필드와 설정을 재사용할 수 있다.

     

    이는 생각보다 굉장히 강력하고 간단한 기능으로, 중복 제거와 코드의 재사용성을 매우 높인다.

    class FeedCreate(BaseModel):
        title: str
        content: str
        image_urls: Optional[List[str]] = []
    
    
    class FeedUpdate(BaseModel):
        title: str
        content: str
        image_urls: Optional[List[str]] = []
    
    
    class FeedInDB(FeedCreate):
        pass
    
    
    class FeedResponse(FeedCreate):
        id: int
        author_email: str
        author_nickname: str
        image_urls: Optional[List[str]]

    추가로 BaseModel은 JSON 직렬화/역직렬화를 직접 지원하기 때문에 매우 편리하게 사용할 수 있다.

     

    FastAPI 라우터의 상속

     

    라우터 상속은 API 엔드포인트를 할당하거나 통합할 때 주로 사용되는데,

    router = APIRouter()

    와 같이 APIRouter 객체를 생성한 뒤 다음처럼 데코레이터로 엔드포인트를 간단히 정의할 수 있다.

    @router.post("/create", response_model=CommentResponse)

    이후 FastAPI의 app 객체에 포함시킴으로써 해당 객체를 통합시켜 다룰 수 있게 된다.

    app.include_router(auth_router.router, prefix="/api/auth", tags=["auth"])
    app.include_router(feed_router.router, prefix="/api/feed", tags=["feed"])
    app.include_router(comment_router.router, prefix="/api/comment", tags=["comment"])
    ...

    이렇게 하면 해당 라우터의 엔드포인트에 prefix를 적용할 수 있으며,

     

    태그를 이용해 API 문서에서의 그룹화 역시 진행할 수 있다.

     

    Dependency Injection

     

    FastAPI의 의존성 주입은 fastapi 라이브러리에서 지원하는 Depends() 함수를 이용해 간단하게 처리된다.

     

    예를 들면 아래와 같은 코드에서,

    @router.post("/create", response_model=CommentResponse)
    def create_comment(
        comment: CommentCreate,
        db: Session = Depends(get_db),
        email: str = Depends(auth_service.get_current_user_authorization),
    ):
        return comment_service.create_comment(db, comment, email)

    Depends(get_db)는 create_comment 함수가 호출될 때 미리 만들어둔 get_db함수를자동으로 실행한 뒤

     

    그 결과를 db에 할당한다. 이렇게 하면 db 변수는 이후의 함수에서 사용할 Session 객체를 가지게 되는 식이다.

     

    그 아랫줄의 email 변수에서는 역시 미리 만들어둔 함수를 이용해 인증 정보를 가져와 이메일을 추출하는 함수를 주입한다.

     

    이 부분 역시 너무 간편해서 오히려 헷갈리는 정도다.

     

    완전히 익숙해질 때까지 몇 번이고 이 글을 봐야겠다.

     

    Summary

     

    이렇게 해서 SQLAlchemy, Pydantic, 그리고 라우터의 상속과 의존성 주입에 대해 짧게 정리해 보았다.

     

    파이썬을 이용한 개발은 자바에 비해 길이가 짧고 함축적인 의미가 많아 쉽게 놓치곤 하는 것 같다.

     

    빨리 익숙해지는 게 답이겠지.

     

    앞으로도 조금씩 구현하고 개선하면서 FastAPI를 놓지 말아야겠다고 생각했다.

     

    끝!

    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/06   »
    1
    2 3 4 5 6 7 8
    9 10 11 12 13 14 15
    16 17 18 19 20 21 22
    23 24 25 26 27 28 29
    30
    글 보관함