8/29(금) - DB 마이그레이션(Alembic) 도입 및 초기 스키마 생성
오늘은 여름방학 중 마지막 회의날이다....
벌써개강이라니 난 마음의 준비가 안됐는걸,,,ㅜㅜ
이번 회차 작업 내용은 다음과 같다.
1. 배경
졸업 프로젝트에서 처음에는 Base.metadata.create_all(bind=engine) 방식으로 SQLite 데이터베이스를 생성해 사용했다.
하지만 이 방식은 단순히 테이블이 없으면 새로 생성할 뿐,
이후 모델 스키마가 변경될 경우(컬럼 추가/수정/삭제 등) 이를 추적하거나 자동 반영할 수 없었다.
팀 단위 협업에서는 데이터베이스 스키마가 변경될 때마다 팀원들이 같은 환경을 유지하기 어렵고,
수작업으로 DROP TABLE 후 다시 create_all()을 실행해야 하는 불편함이 있었다.
👉 따라서 Alembic이라는 마이그레이션 도구를 도입하여 DB 변경 이력을 코드로 관리하고,
버전 간 업그레이드/다운그레이드를 자동화하도록 수정함
2. Alembic 도입의 필요성
- 스키마 변경 이력 관리 : 컬럼 추가/수정/삭제 기록을 리비전 파일로 남길 수 있음
- 협업 효율 : 팀원 간 DB 구조를 동일하게 유지 가능 (alembic upgrade head 한 줄로 통일)
- 롤백 지원 : 문제가 생기면 손쉽게 이전 버전으로 되돌릴 수 있음
- 데이터 유지 : 기존 데이터는 보존하면서 스키마만 갱신 가능
3. 설치 및 초기 설정
sudo pip install alembic
alembic init migrations
- 프로젝트 루트에 alembic.ini와 migrations/ 폴더가 생성됨
- migrations/env.py 파일이 마이그레이션 실행의 핵심 스크립트
4. 환경 설정
4.1 .env 파일
데이터베이스 연결 문자열을 .env에서 관리하도록 설정했다.
# .env
ENVIRONMENT=dev
DATABASE_URL=sqlite:///./database.db
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
OPENAI_API_KEY=sk-xxxxxx
OPENAI_MODEL=gpt-4o-mini
4.2 app/database.py
SQLAlchemy 엔진과 세션 팩토리를 정의하고, .env의 DATABASE_URL을 읽어오도록 수정했습니다.
import os
from dotenv import load_dotenv
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./database.db")
kwargs = {}
if DATABASE_URL.startswith("sqlite"):
kwargs["connect_args"] = {"check_same_thread": False}
engine = create_engine(DATABASE_URL, **kwargs)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
4.3 app/models/common_models.py
Alembic autogenerate 시 제약조건 이름이 매번 달라지는 문제를 막기 위해 Naming Convention을 도입했다.
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import MetaData
NAMING_CONVENTION = {
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(constraint_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
class Base(DeclarativeBase):
metadata = MetaData(naming_convention=NAMING_CONVENTION)
4.4 migrations/env.py
- .env의 DATABASE_URL을 로드
- SQLite에서 안전하게 ALTER 작업을 지원하기 위해 render_as_batch=True 설정
- 모든 모델(market_models, festival_models, recommend_models)을 import하여 autogenerate 시 테이블 인식 보장
from alembic import context
from sqlalchemy import create_engine, pool
from dotenv import load_dotenv
from app.models.common_models import Base
import app.models.market_models
import app.models.festival_models
import app.models.recommend_models
load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./database.db")
IS_SQLITE = DATABASE_URL.startswith("sqlite")
target_metadata = Base.metadata
def run_migrations_online():
connectable = create_engine(DATABASE_URL, poolclass=pool.NullPool)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True,
compare_server_default=True,
render_as_batch=IS_SQLITE,
)
with context.begin_transaction():
context.run_migrations()
5. 첫 마이그레이션 생성 및 적용
5.1 기존 DB 삭제 (개발용)
rm -f database.db
5.2 리비전 파일 생성
alembic revision --autogenerate -m "init schema"
출력 로그:
INFO [alembic.autogenerate.compare] Detected added table 'categories'
INFO [alembic.autogenerate.compare] Detected added table 'markets'
INFO [alembic.autogenerate.compare] Detected added table 'products'
INFO [alembic.autogenerate.compare] Detected added table 'festivals'
INFO [alembic.autogenerate.compare] Detected added table 'regions'
INFO [alembic.autogenerate.compare] Detected added table 'recommendations'
Generating /.../migrations/versions/cab00a13d2bb_init_schema.py ... done
5.3 마이그레이션 적용
alembic upgrade head
출력 로그:
INFO [alembic.runtime.migration] Running upgrade -> cab00a13d2bb, init schema
→ database.db 안에 모든 테이블과 인덱스가 생성됨
6. 이후 워크플로
- 모델 변경 → 새로운 리비전 생성
alembic revision --autogenerate -m "add column foo to products"
- 적용
alembic upgrade head
- 문제 발생 시 롤백
alembic downgrade -1
7. 팀 협업 규칙
- 모델 변경 시 반드시 Alembic 리비전 생성 후 Git에 푸시
- 팀원은 Pull 받은 후 alembic upgrade head 실행으로 DB 스키마 동기화
- 데이터는 seed_dev.py로 공통 샘플 세팅
- .env는 로컬에서 관리, 대신 .env.example를 Git에 포함시켜 공유
8. 정리
- create_all()에서 Alembic으로 넘어오니 스키마 관리가 훨씬 체계적이고 팀 협업에 적합해졌음
- SQLite에서는 render_as_batch=True가 필수라는 점, Pydantic v2 변경으로 인한 경고 처리 등을 경험하면서 실무에서 마이그레이션 세팅 시 주의해야 할 부분을 배웠음
- 이제는 DB 구조 변경이 있더라도 팀원 전원이 쉽게 동일 환경을 유지할 수 있다는 안정감이 생김
'주전공 > 캡스톤디자인과창업프로젝트' 카테고리의 다른 글
| [이화여대 캡스톤디자인과창업프로젝트] 기술블로그 | 소소행 : RAG를 활용한 소도시 여행지 추천 서비스 (0) | 2025.11.24 |
|---|---|
| 그로쓰 기록(1) : 마켓 기능 구축 및 장바구니 & 찜하기 확장 (0) | 2025.10.02 |
| 여름방학 기록(6): 데이터베이스 초기화 | DB Schema 생성 (0) | 2025.08.24 |
| 여름방학 기록(5): FastAPI 백엔드 기본 개발환경 세팅 및 서버 띄우기 | 코드 실행 및 연동 1차 테스트 + Mock 실행 확인 (0) | 2025.08.18 |
| 여름방학 기록(4): BE 개발 시작 | API Endpoint Listup + FastAPI code (0) | 2025.08.17 |