FastAPI 개발자 tiangolo는 FastAPI를 어떻게 사용할까 궁금해서 찾아본 프로젝트
https://github.com/tiangolo/full-stack-fastapi-postgresql
이번 게시글에서는 프로젝트 데이터베이스 마이그레이션 도구인 alembic을 어떻게 적용하였는지 분석하려고 함
alembic 관련 파일은 아래와 같음
```
.env # 환경 변수 설정이 담긴 파일 → DB 설정을 이 파일에서 확인 가능
alembic.ini # Alembic의 설정 파일로, 데이터베이스 마이그레이션 설정을 정의
app
└── alembic # 데이터베이스 마이그레이션을 관리하는 Alembic 설정 파일 및 스크립트가 저장된 디렉토리
├── env.py # alembic 실행 시 실행되는 파일로, SQLAIchemy의 Engine을 설정하고 마이그레이션 스크립트 실행
└── versions # 버전 별 데이터베이스 마이그레이션 스크립트가 저장된 디렉토리
└── e2412789c190_initialize_models.py # 데이터 베이스 테이블 및 인덱스 생성 스크립트
└── models.py # ORM 도구에서 데이터 모델을 정의하는데 사용되는 파일로, 이 파일의 모델과 DB 차이를 바탕으로 마이그레이션 스크립트가 생성됨
```
.env
파이썬에서는 프로젝트 별로 환경변수를 관리하기 위하여 .env파일을 널리 사용함
.env파일에 설정된 alembic에 사용되는 환경변수는 아래와 같음
POSTGRES_SERVER=db
POSTGRES_USER=postgres
POSTGRES_DB=app
POSTGRES_PASSWORD=changethis
alembic.ini
alembic.ini 파일은 Alembic 데이터베이스 마이그레이션 도구의 설정 파일로, 주로 데이터베이스 연결 및 마이그레이션 관련 설정을 포함
- 일반적으로 사용되는 설정
- 데이터베이스 연결 정보 설정 (sqlalchemy.url)
- 마이그레이션 스크립트 경로 설정 (script_location)
- 로깅 설정 (loggers, handlers, formatters)
- 버전 관리 설정 (version_table)
- 그 외 커스텀 설정
tiangolo 백엔드 프로젝트의 alembic.ini는 아래와 같은 설정으로 구성되어 있음
[alembic]
script_location = app/alembic
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
env.py
alembic 실행 시 실행되는 파일로, SQLAIchemy의 Engine을 설정하고 마이그레이션 스크립트 실행
- 주요 작업
- 모듈 및 패키지 가져오기
- context.config를 사용하여 Alembic Config 객체를 설정
이 객체는 사용 중인 .ini 파일 내의 값을 제공
- fileConfig(config.config_file_name)을 호출하여 Python 로깅을 설정
.ini 파일의 로깅 구성을 기반으로 로그 기능을 활성화
- app.models에서 SQLModel을 가져와 target_metadata로 설정
마이그레이션 스크립트에서 사용할 데이터베이스 모델의 메타데이터를 지정
- get_url함수는 .env(환경 변수)를 통해 PostgreSQL 데이터베이스 연결 URL을 생성
- run_migrations_offline 함수는 오프라인 모드에서 마이그레이션을 실행
- run_migrations_online 함수는 온라인 모드에서 마이그레이션 실행
- context.is_offline_mode()를 사용하여 현재 마이그레이션 모드가 오프라인인지 확인하고, 그에 따라 run_migrations_offline 또는 run_migrations_online 함수를 호출하여 마이그레이션을 실행
versions / e2412789c190_initialize_models.py
데이터 베이스 테이블 및 인덱스 생성 스크립트
일반적으로 alembic을 이용하여 마이그레이션 스크립트를 자동적으로 생성하면 models.py파일을 기반으로 테이블 생성/삭제 스크립트만 생성됨
index 생성 스크립트는 수동으로 추가했을 것으로 예상됨
alembic이 뭔지 모르는 경우 alembic 소개 및 기초 사용법 포스팅 참고
"""Initialize models
Revision ID: e2412789c190
Revises:
Create Date: 2023-11-24 22:55:43.195942
"""
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from alembic import op
revision = "e2412789c190"
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"user",
sa.Column("email", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("is_superuser", sa.Boolean(), nullable=False),
sa.Column("full_name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sa.Integer(), nullable=False),
sa.Column(
"hashed_password", sqlmodel.sql.sqltypes.AutoString(), nullable=False
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_user_email"), "user", ["email"], unique=True)
op.create_table(
"item",
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("owner_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(
["owner_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
)
def downgrade():
op.drop_table("item")
op.drop_index(op.f("ix_user_email"), table_name="user")
op.drop_table("user")
참고 : FastAPI 개발자가 직접 개발한 FastAPI backend 시리즈
FastAPI 개발자가 직접 개발한 FastAPI backend 프로젝트 구조
FastAPI 개발자가 직접 개발한 FastAPI backend alembic
FastAPI 개발자가 직접 개발한 FastAPI backend DB 초기화 방법
FastAPI 개발자가 직접 개발한 FastAPI backend pyproject.toml
FastAPI 개발자가 직접 개발한 FastAPI backend 설정파일 config.py
FastAPI 개발자가 직접 개발한 FastAPI backend 데이터모델 models.py