본문 바로가기
Fast API

[FastAPI] SQLModel 배우기

by 붕어사랑 티스토리 2023. 12. 13.
반응형

https://sqlmodel.tiangolo.com/tutorial/fastapi/simple-hero-api/

 

Simple Hero API with FastAPI - SQLModel

SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.

sqlmodel.tiangolo.com

1. SQL Model이란

fastapi에서 가장 큰 단점은, 데이터베이스의 스키마와, API의 스키마를 각각 SQLAlchemy, Pydantic으로 따로 작성해주어야 한다는 점이다. 이로인해 코드 유지보수에 어려움이 있었다.

 

SQLModel이란, SQLAlchemy와 Pydantic을 서로 합친 것이다. 두 패키지 위에 하나의 레이어를 올려서 두개다 작동하도록 설계되었다.

 

이 패키지를 만든 사람은 fastapi 개발자와 동일하다. 멋져요 아주.

 

 

 

2. 설치방법

pip install sqlmodel

 

위 한줄이면 된다. 내부적으로 sqlalchemy와 pydantic을 같이 받아주므로 다른 패키지는 신경쓰지 말자.

 

 

 

3. 사용법

 

공식문서에 나온 예제는 다음과 같다

from typing import Optional

# One line of FastAPI imports here later 👈
from sqlmodel import Field, Session, SQLModel, create_engine, select

class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    secret_name: str
    age: Optional[int] = Field(default=None, index=True)


sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, echo=True, connect_args=connect_args)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)

# Code below omitted 👇

 

 

 

가장 중요하게 볼 것은 아래 코드이다.

class Hero(SQLModel, table=True):

 

위 코드는 Hero가 SQLMode 상속받았다. 그리고 table값을 True로 주면, 데이터베이스와 API에 모두 활용할 수 있음을 의미한다.

 

 

 

 

아래 코드에서 id가 primary_key인데 Optional을 준 것은, 데이터베이스에서 primary_key는 반드시 필요하지만, API에서는 필요없기에 Optional로 자료형을 설정해야 한다.

    id: Optional[int] = Field(default=None, primary_key=True)

 

 

 

 

아래코드도 몹시 중요하다. 여지껏 SQLModel을 상속받고, table이 True인 애들을 실제 데이터베이스에서 테이블로 삽입해준다.

만약 엔진을 만들 때 echo값을 True로 주면, 실제 엔진에 들어가는 SQL문이 로그로 나온다.

def create_db_and_tables():
    SQLModel.metadata.create_all(engine)

 

 

 

 

 

 

 

 

3. 실제 사용

 

앞서 살펴본 create_db_and_tables는 서버가 시작될 때 처음 한번 불려야 한다. lifespan을 이용하여 해당 함수를 호출하자

lifespan은 starup과 shutdown의 데코레이터를 대체하는 새로운 데코레이터이다.

 

yield를 기준으로 yield앞 코드는 서버가 시작될 때, yield 뒤에는 서버가 종료 될 때 호출된다.

from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app:FastAPI):
    create_db_and_tables()
    yield
    print("finish")

app = FastAPI(lifespan=lifespan)



@app.post("/heroes/")
def saveHero(hero : Hero):
    with Session(engine) as session:
        session.add(hero)
        session.commit()
        session.refresh(hero)
        return result

 

 

위 코드를 보면 Hero가 API에서도 활용되고 데이터베이스에서도 활용됨을 알 수 있다.

 

 

 

FastAPI는 정말 어디까지 발전하려는건가. 대단한 프레임워크다

 

 

 

 

4. swagger에서의 사용

허나 한가지 문제가 있다. swagger에서 바로 Hero를 사용하면 api에서 id값을 요구하는데, api에서는 사실상 키값을 입력해줄 필요가 없다. 공식문서에서 이를 해결하려면 아래처럼 상속을 이용해 해결하라고 한다.

 

대충보면

 

Base : 뼈대

Base없음 : 테이블용

Create : Base를 그대로 가져오되, Create를 붙여 가독성을 높임

Read : 테이블 형태를 가져오되, table이 False이고 Read를 붙여 가독성을 높임

# Code above omitted 👆

class HeroBase(SQLModel):
    name: str = Field(index=True)
    secret_name: str
    age: Optional[int] = Field(default=None, index=True)


class Hero(HeroBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)


class HeroCreate(HeroBase):
    pass


class HeroRead(HeroBase):
    id: int

# Code below omitted 👇
반응형

댓글