FastAPI/데이터베이스

ORM 적용 - DELETE API

hyunai 2026. 6. 26. 17:19
# repository.py

from sqlalchemy import select, delete

def delete_todo(session: Session, todo_id: int) -> None:
    session.execute(delete(ToDo).where(ToDo.id == todo_id))
    session.commit()

session.execute() 완전 이해하기


먼저 전체 맥락 이해하기

지금까지 배운 SQLAlchemy 조회 방법들

SQLAlchemy 실행 메서드 비교

메서드 용도  반환값
session.scalars() 조회 (여러 개) 객체 목록
session.scalar() 조회 (한 개) 객체 하나
session.execute() 뭐든 다 실행 Result 객체

session.execute() 는 조회/추가/수정/삭제 전부 다 실행할 수 있는 만능 메서드


session.execute() 구조 분해

현재 코드 완전 분해

session.execute(delete(ToDo).where(ToDo.id == todo_id))
#       ↑        ↑              ↑
#    실행해줘   무엇을?      어떤 조건으로?
#            ToDo 삭제     id가 todo_id인 것만

자연어로 읽으면:

"ToDo 테이블에서 id가 todo_id인 행을 삭제하는 SQL을 실행"


내부적으로 어떤 SQL이 실행되냐면

실제 실행되는 SQL

# Python 코드
session.execute(delete(ToDo).where(ToDo.id == todo_id))

# SQLAlchemy가 자동으로 번역한 SQL
DELETE FROM todo WHERE todo.id = 1
#                             ↑
#                          todo_id 값

echo=True 설정 덕분에 콘솔에 이런 로그가 찍힌다.


scalars vs execute 차이

scalars vs execute 비교

# scalars → 조회 전용, 결과를 Python 객체로 바로 반환
todos = session.scalars(select(ToDo))
# [ToDo(id=1...), ToDo(id=2...)] ← 바로 객체 리스트

# execute → 만능, Result 객체 반환
result = session.execute(select(ToDo))
# <sqlalchemy.engine.result.ChunkedIteratorResult> ← Result 객체
# .scalars(), .fetchall() 등으로 꺼내야 함

# 삭제할 때는 반환값이 필요 없으니까 그냥 실행만
session.execute(delete(ToDo).where(ToDo.id == todo_id))

delete() 문법 더 이해하기

delete() 문법 구조

from sqlalchemy import delete

delete(ToDo)                        # ToDo 전체 삭제 (위험)
delete(ToDo).where(ToDo.id == 1)    # id가 1인 것만 삭제
delete(ToDo).where(ToDo.is_done == True)  # 완료된 것만 삭제

delete().where() 동작 흐름

delete(ToDo)
    ↓
"todo 테이블에서 삭제할 준비"
    ↓
.where(ToDo.id == todo_id)
    ↓
"id가 todo_id인 것만"
    ↓
session.execute()
    ↓
실제 SQL 실행
"DELETE FROM todo WHERE id = 1"
    ↓
session.commit()
    ↓
DB에 반영 완료

select / delete / update 비교

CRUD 각각 어떻게 쓰는지

from sqlalchemy import select, delete, update

# 조회 (Read)
session.scalars(select(ToDo).where(ToDo.id == 1))

# 삭제 (Delete)
session.execute(delete(ToDo).where(ToDo.id == 1))

# 수정 (Update)
session.execute(
    update(ToDo)
    .where(ToDo.id == 1)
    .values(is_done=True)
)

# 추가 (Create) → execute 대신 add 사용
session.add(ToDo(contents="할일", is_done=False))

💡 핵심 요약:
session.execute() = SQL 구문을 실행하는 만능 메서드
delete(ToDo).where(조건) = 조건에 맞는 행 삭제 SQL 생성
session.execute() 만으로는 DB에 안 반영되고, session.commit() 까지 해야 실제 반영.


# main.py

# delete 성공 상태 코드 : 204
# 204는 응답 받는 body가 없기 때문에 return이 없거나 빈 return을 줘도 된다.
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo_handler(
        todo_id: int,
        session: Session = Depends(get_db),):
    # 삭제하기 위해선 todo id가 유효한지 확인
    todo: ToDo | None = get_todo_by_todo_id(session=session, todo_id=todo_id)
    if not todo:
        raise HTTPException(status_code=404, detail="Todo Not Fount")

    delete_todo(session=session, todo_id=todo_id)
  • 아이디를 먼저 조회를 해서 todo를 확인한 후 투두가 있으면 delete 요청을 하고 todo가 없으면 404를 리턴
  • 204인 경우에는 별도로 return문을 적지 않아도 응답으로 반환할 데이터가 없기 때문에 먼저 처리를 해주면 에러를 발생시키고 그게 아닌 경우에는 데이터를 삭제해줄 수 있어 코드 가독성을 위해 에러문을 위로 처리(if no todo:)

swagger 확인

'FastAPI > 데이터베이스' 카테고리의 다른 글

ORM 적용 - PATCH API  (0) 2026.06.25
ORM 적용 - POST API  (0) 2026.06.24
파이참 - Refactoring  (0) 2026.06.16
ORM 적용 - GET 단일 조회 API  (0) 2026.06.16
ORM 적용 - HTTP Response 처리  (1) 2026.06.14