어제보다 한걸음 더

Python 3.11 + Fast API를 이용한 게시판 CRUD 구현 본문

회고

Python 3.11 + Fast API를 이용한 게시판 CRUD 구현

지안22 2024. 3. 8. 16:00

여태까지는 Java/Spring으로만 서버를 구현했었다.

회사 입사 테스트 과제를 계기로, 평소부터 구현해보고 싶었던 Python을 이용해서 게시판 CRUD를 구현해보았다.

 

Fast API 프레임 워크 선택 이유

파이썬 프레임워크로는 보통 Flask, FastAPI, Django 중 하나로 선택한다.

이번 과제는 SQL 과제를 포함해서 3일이라 시간이 좀 촉박했다.

때문에 기본 기능을 빠르게 구현할 수 있고, Swagger로 자동 문서화가 제공되는 Fast API를 선택했다.

 

데이터베이스는 SQLite를 지정해주셨는데, 이 또한 가벼운 DB라 설정 상 오류 발생 가능성이 적어서 지정해주신 것 같다.

SQLite라는 데이터베이스도 처음 다뤄봐서 좋았다.

 

구현 내용

DB 테이블

유저, 게시판

REST API

디렉터리 구조

.
└── app
    ├── crud.py     
    ├── database.py 
    ├── main.py     
    ├── models.py   
    └── schema.py

요구사항

간단한 게시판 CRUD를 만들면 됐다.

유저 CRUD는 만들지 않아도 된다고 들었지만, 미리 DB에 넣어놓은 유저가 날아갔을 경우를 대비해서 유저 CR은 구현했다.

  • 게시판 생성 시 user_name이 필요하기 때문이다.

 

어려웠던 점

간단한 게시판 CRUD 구현이기 때문에 어려웠던 점만 적어두려고 한다. (소스코드)

1. 구조 이해

.
└── app
    ├── crud.py      |  Spring MVC에서 Service + Repository 역할
    ├── database.py  |  Java/Spring에서 DB설정하는 yml파일 역할
    ├── main.py      |  Spring MVC에서 Controller 역할
    ├── models.py    |  Spring에서 Entity 역할
    └── schema.py    |  Spring에서 DTO 역할

이렇게 이해했는데 혹시 아니라면 알려주시면 감사하겠습니다 🙇‍♀️

2. SQLAlchemy - datetime

테이블을 생성하기 위해 ORM으로 DB에 접근할 수 있도록 편리하게 제공해주는 툴이 SQLAlchemy이다.

# models.py
from sqlalchemy import Column, ForeignKey, Integer, String, DateTime, text
from sqlalchemy.orm import relationship

from database import Base

class User(Base):
    __tablename__  = "users"
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(10), unique=True, nullable=False)
    # 연관관계 설정 one to many
    posts = relationship("Post", back_populates="writer")

class Post(Base):
    __tablename__ = "posts"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(20), nullable=False)
    body = Column(String(1000))
    # 처음 데이터 삽입 시 default로 생성일자 생성.
    created_at = Column(DateTime(timezone=True), default=text("datetime('now','localtime')"))
    # 데이터가 수정 될 때 자동으로 수정일자 업데이트
    modified_at = Column(DateTime(timezone=True), onupdate=text("datetime('now','localtime')"))
    # 자식 테이블이 부모 테이블을 참조.
    writer_id = Column(Integer, ForeignKey("users.id"))
    # 연관관계 설정 
    writer = relationship("User", back_populates="posts")
  1. 테이블 간 연관관계를 설정하는 것도 어려웠고,
    • 나의 기술적 이해도가 낮아서 Java/Spring으로 다룰 때에도 어려워했다.
  2. DB 컬럼에 default로 들어가는 시간을 다루는 것도 어려웠고,
    • 처음에는 stackoverflow에 나온 대로 `func.now()`로 설정했지만 한국 시간으로 안넣어졌다. (UTC 기준)
    • 기존까지는 게시판 구현에 MySQL을 사용했었고, DB 시간을 한국 시간으로 설정해줘서 해결했다.
    • 하지만 이번에 사용한 SQLite는 시간을 설정할 수 없어서 `text()`를 이용해서 SQL 표현식을 직접 입력해서 실행하는 것으로 해결했다.
  3. 현재 시간 넣으려면 왜 `datetime.datetime.now()` 로 해야하는건지도 의문이었다.
    • `from datetime import datetime` 으로 설정해서 `datetime.now()`로 `datetime`을 한번으로 줄이기는 했지만..
    • `datetime`을 왜 두번 쓰는거지..?
  4. `models.py`에서 컬럼을 Nullable로 설정해두면 `schema.py`에서 `Optional[데이터타입] = None`으로 설정해놔야하는 것을 몰라서 삽질을 하기도 했다.

 

느낀점

디테일한 부분에는 애를 먹었지만, 대략적인 구조만 잘 이해하면 Java/Spring과 비슷해서 놀랐다.

과제 덕분에 파이썬으로 게시판 CRUD 구현도 해보고, 늘어지는 취준 생활에 신선함과 뿌듯함이 추가되서 좋았다!

안해봐서 못할 것 같았는데, 결국 해내서 자신감이 상승됐다! 😊

 

아쉬운 점

Response DTO를 보여주고 싶은 속성만 반환하게 하고 싶었는데 전체 속성을 보여주게 되어 아쉬웠다.

models.py에서 각 요청(CRUD)에 대한 Response DTO를 따로 만들고, class Config 속성에 exclude를 추가해서 보여주고 싶지 않은 속성을 추가하면 될 것 같다.

 

소스코드

https://github.com/sudago/-CRUD---Python/blob/main/README.md

참고했던 블로그

Fast API 배우기 23부 - SQL 데이터베이스

FastAPI 파이썬으로 간단하게 웹 API 만들기 - 오픈소스컨설팅 테크블로그