# request.py
from pydantic import BaseModel
class CreateToDoRequest(BaseModel):
contents: str
is_done: bool
# orm.py
from schema.request import CreateToDoRequest
# 요청 받은 requestBody를 ORM 객체로 변환해주는 클래스 method
@classmethod
def create(cls, request : CreateToDoRequest) -> "ToDo":
return cls(
contents=request.contents,
is_done=request.is_done,
)
- 이 classmethod는 request를 그대로 전달을 받는다.
- return에 cls에 맞는 데이터로 매핑을 해주면 되는데 앞서 id 값은 데이터베이스에 의해 자동으로 결정하도록 했기 때문에 별도로 지정해주지 않는다.
- Pydantic을 통해 전달 받은 Pydantic으로 request를 받아서 이제 ORM 객체를 생성해주게 된다.
- 여기까지는 데이터베이스에 실제로 저장을 한 것은 아니다.
@classmethod 와 cls
파이썬 메서드 종류부터 이해하기
메서드 3종류 비교
| 종류 | 선언 방식 | 첫 번째 파라미터 | 접근 가능한 것 |
| 일반 메서드 | 그냥 def | self (인스턴스) | 인스턴스 속성 |
| 클래스 메서드 | @classmethod | cls (클래스) | 클래스 자체 |
| 정적 메서드 | @staticmethod | 없음 | 둘 다 접근 불가 |
self 랑 cls 차이부터 이해하기
self vs cls 비교
class ToDo:
# 일반 메서드 → self = 만들어진 객체 자신
def get_contents(self):
return self.contents # 객체의 속성에 접근
# 클래스 메서드 → cls = ToDo 클래스 자체
@classmethod
def create(cls, request):
return cls(...) # ToDo(...) 와 완전히 같은 말
self vs cls 시각화
self = 만들어진 붕어빵 (인스턴스)
cls = 붕어빵 틀 (클래스 자체)
ToDo 클래스 (붕어빵 틀)
↓ ToDo() 호출
todo 인스턴스 (붕어빵)
↓
todo.contents, todo.is_done 접근 가능
@classmethod 가 뭔지
classmethod 없을 때 vs 있을 때
# classmethod 없이 객체 생성
todo = ToDo(
contents=request.contents,
is_done=request.is_done,
)
# classmethod로 객체 생성
todo = ToDo.create(request=request)
둘 다 결과는 같다. 차이는 "생성 로직을 클래스 안에 캡슐화했냐"
cls(...) 가 왜 ToDo(...) 랑 같냐면
cls 동작 원리
class ToDo(Base):
@classmethod
def create(cls, request: CreateToDoRequest) -> "ToDo":
# ↑
# cls = ToDo 클래스 자체를 가리킴
return cls( # = ToDo() 랑 완전히 같음
contents=request.contents,
is_done=request.is_done,
)
# 실제로 이렇게 호출하면
todo = ToDo.create(request=request)
# 내부적으로 이렇게 동작하는 것과 같음
todo = ToDo(
contents=request.contents,
is_done=request.is_done,
)
왜 굳이 @classmethod로 만드냐면
classmethod 장점
# 밖에서 직접 생성하는 방식
@app.post("/todos")
def create_todo_handler(request: CreateToDoRequest):
# 핸들러가 ToDo 생성 방법을 알아야 함
todo = ToDo(
contents=request.contents,
is_done=request.is_done,
)
# 만약 나중에 필드가 추가되면?
# 모든 핸들러를 다 찾아서 수정해야 함
# classmethod로 만드는 방식
@app.post("/todos")
def create_todo_handler(request: CreateToDoRequest):
# 핸들러는 그냥 create()만 호출하면 됨
todo = ToDo.create(request=request)
# 나중에 필드 추가되면 create()만 수정하면 됨
classmethod 쓰는 이유
| 이유 | 설명 |
| 캡슐화 | 생성 로직이 ToDo 클래스 안에 모여있음 |
| 유지보수 | 생성 방법 바뀌면 create()만 수정하면 됨 |
| 가독성 | ToDo.create(request) 가 ToDo(contents=..., is_done=...) 보다 읽기 쉬움 |
반환 타입 -> "ToDo" 에서 왜 따옴표가 붙냐면
따옴표 있는 타입 힌트
@classmethod
def create(cls, request: CreateToDoRequest) -> "ToDo":
# ↑
# 따옴표로 감싼 이유:
# 자기 자신 클래스를 타입 힌트로
# 쓸 때 따옴표 필요
# 왜냐면 ToDo 클래스가 아직 완전히 정의되기 전에
# 자기 자신을 참조하려고 하면 에러가 나기 때문
# 따옴표로 감싸면 "나중에 확인해줘" 라는 의미
전체 흐름 한눈에 보기
create() 전체 동작 흐름
POST /todos 요청
{
"contents": "FastAPI 공부",
"is_done": false
}
↓
create_todo_handler(request=CreateToDoRequest)
↓
ToDo.create(request=request) 호출
↓
cls = ToDo 클래스 자체
cls(contents="FastAPI 공부", is_done=False)
↓
ToDo 인스턴스 생성
todo.contents = "FastAPI 공부"
todo.is_done = False
↓
session에 저장
💡 핵심 요약:
@classmethod = 인스턴스 없이 클래스 이름으로 바로 호출할 수 있는 메서드
cls = 클래스 자체 (self는 인스턴스, cls는 클래스)
cls(...) = ToDo(...) 랑 완전히 같은 말
쓰는 이유 = 생성 로직을 클래스 안에 모아서 유지보수를 쉽게 하기 위해
# main.py
@app.post("/todos", status_code=201)
# FastAPI가 알아서 reqeustBody를 CreateToDoRequest에 넣어서 처리를 해준다.
def create_todo_handler(request: CreateToDoRequest):
todo: ToDo=ToDo.create(request=request)
- 변환된 ORM 객체를 통해서 DB에 실제로 저장해달라는 요청을 한다.
# repository.py
# todo를 ORM 객체로 전달을 받도록 설정해주고 return을 해준다.
def create_todo(session: Session, todo:ToDo) -> ToDo:
# 생성한 ORM 객체를 Session Object에 먼저 추가를 해준다.
session.add(instance=todo)
# db save
# 이때 DB상의 ToDo id 값은 할당이 되어 저장이 된다.
session.commit()
# db를 다시 read ->이때 지금 메모리 상의 todo_id 결정
session.refresh(instance=todo)
return todo
# request.py
from pydantic import BaseModel
class CreateToDoRequest(BaseModel):
# id 값은 DB에서 자동으로 올려주기 때문에 id 없애기
contents: str
is_done: bool
# main.py
@app.post("/todos", status_code=201)
# FastAPI가 알아서 reqeustBody를 CreateToDoRequest에 넣어서 처리를 해준다.
def create_todo_handler(
request: CreateToDoRequest,
session: Session = Depends(get_db)
) -> ToDoSchema:
todo: ToDo=ToDo.create(request=request) # id=None
todo: ToDo=create_todo(session=session, todo=todo) # id=int
return ToDoSchema.model_validate(todo)
- 첫번째 todo는 아직 id 값이 none이다.
- 두번째 todo에서는 create_todo에서 정해진 id 값이 들어간 todo
- session을 통해서 todo에 todo가 실제로 DB에 저장이 되고 리프레쉬된 두번째 todo가 이 변수에 다시 할당이 되게 된다.
swagger에서 확인


'FastAPI > 데이터베이스' 카테고리의 다른 글
| ORM 적용 - DELETE API (0) | 2026.06.26 |
|---|---|
| ORM 적용 - PATCH API (0) | 2026.06.25 |
| 파이참 - Refactoring (0) | 2026.06.16 |
| ORM 적용 - GET 단일 조회 API (0) | 2026.06.16 |
| ORM 적용 - HTTP Response 처리 (1) | 2026.06.14 |