포스트

[DB] SQLModel로 데이터베이스 다루기 <2>

공식문서 참조

1. INSERT INTO…

테이블을 만들었으니 데이터를 넣어보자. 순서는 다음과 같다.

  1. Engine을 통해 Session을 만든다.
  2. Session을 통해 쿼리를 작성한다.
  3. commit
  4. Session 종료

1.1 Session 반환 함수

1
2
3
4
5
6
7
async def get_async_session():
    async_session = async_sessionmaker(
        bind=async_engine,
        class_=AsyncSession,
    )
    async with async_session() as session:
        yield session

비동기적으로 만들었기 때문에 yield로 반환한다.

1.2 엔드포인트에서 Depends로 활용

1
2
3
4
5
6
7
8
9
10
@app.post("/", status_code=status.HTTP_201_CREATED)
async def create_heros(session:Annotated[AsyncSession, Depends(get_async_session)]):
    hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
    hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
    hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)

    async with session.begin():
        session.add_all([hero_1, hero_2, hero_3])

    return {"msg": "Heros created"}

해당 엔드포인트에 post 요청이 들어오면 미리 만들어둔 히어로를 db에 추가한다.

Depens 를 활용하면 의존성 주입을 통해 간단하게 구현 가능하다.

자동 커밋, 롤백을 위해 session.begin() 으로 추가한다.

1.3 결과

만들어준 히어로들이 추가됐다.

2. SELECT

위에서 입력한 데이터들을 조회해보자.

1
2
3
4
5
6
7
8
9
10
from sqlmodel import select

@app.get("/", status_code=status.HTTP_200_OK)
async def get_heros(session:Annotated[AsyncSession, Depends(get_async_session)]):
    async with session.begin():
        statement = select(Hero)
        results = await session.exec(statement)
        heros = results.all()
        
    return heros

sqlmodelselect 를 사용해 SQL 문법의 SELECT를 구현할 수 있다.

SQLModel을 상속한 클래스를 select에 매개변수로 넘겨주면 테이블의 모든 컬럼을 불러오게 된다.

이때 execute 한 결과물에 .all() 메서드를 사용하면 모든 객체를 리스트로 불러올 수 있다. 종류는 아래와 같다.

  • .all(): 모든 행을 리스트로 반환
  • .first(): 결과의 첫 번째 행만 반환
  • .one(): 결과 중 단 하나의 행만 반환. 하나의 행보다 많으면 오류 발생
  • .one_or_none(): 하나의 행 또는 None을 반환. 여러 행이면 오류
  • .fetchmany(size) : 지정한 사이즈의 갯수만큼 반환함.
  • .partitions(size): 지정한 size 만큼의 쿼리 결과를 그룹으로 나누어 처리.

.fetchall() 로 조회한 결과물들이다. 잘 조회된다.

3. WHERE

SQL 문에서 WHERE 은 특정 조건의 데이터만 검색하기 위한 쿼리다.

1
2
3
4
5
6
7
8
9
10
11
@app.get("/{word}", status_code=status.HTTP_200_OK)
async def get_heros(
    session:Annotated[AsyncSession, Depends(get_async_session)],
    word: str
    ):
    async with session.begin():
        statement = select(Hero).where(Hero.name == word)
        results = await session.exec(statement)
        heros = results.fetchall()
        
    return heros

위의 api를 살짝 변형해 url에서 특정 word를 검색어로 활용해 get 메서드를 사용하게 만들었다.

이때 word와 테이블의 객체의 name 이 같은 행만 반환하게 된다.

잘 반환된다.

3.1 SELECT vs WHERE

이 두 가지 sql 문을 사용할 때는 다음과 같은 팁이 있다.

  1. SELECT 는 데이터베이스에서 특정 열을 리턴하기 위해 사용한다.

    1
    
     statement = select(Hero.name) ... # 히어로들의 이름을 리턴함.
    
  2. WEHRE 은 데이터베이스에서 특정 행을 리턴하기 위해 사용한다.

    1
    
     statement = select(Hero).where(Hero.name == "Deadpond") # 특정 이름을 가진 히어로 정보를 리턴함.
    

3.2 조건문

== 뿐만이 아니라 부등호, 부정문을 사용한 조건문도 가능하다.

  1. 1
    
     statement = select(Hero).where(Hero.name != "Deadpond") # 특정 히어로의 이름이 아닌 경우를 리턴함
    
  2. 부등호

    1
    
     statement = select(Hero).where(Hero.age > 35) # 35세 초과의 히어로만 리턴함.
    

3.3 중복 WHERE

where 을 중복으로 사용하는것도 가능하다.

1
statement = select(Hero).where(Hero.age >= 35).where(Hero.age < 40) # 35세 이상, 40세 미만의 히어로를 리턴함

다른 표현

1
statement = select(Hero).where(Hero.age >= 35, Hero.age < 40)

3.4 _or

_or 을 임포트하면 or 조건도 사용 가능하다.

1
2
3
4
from sqlmodel import Field, Session, SQLModel, create_engine, or_, select

statement = select(Hero).where(or_(Hero.age <= 35, Hero.age > 90))
# 35세 이하, 혹은 90세 초과 히어로를 리턴한다.


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.