FastAPI에서 SQLAlchemy를 사용하여 테이블을 생성하는 방법
1. Base.metadata.create_all(bind=engine)
1) 설명:
- SQLAlchemy의 create_all() 메서드는 Base 클래스를 상속받은 모든 모델에 대해 테이블을 생성한다.
- 일반적으로 FastAPI에서 engine을 정의하고 Base.metadata.create_all(bind=engine)을 호출하면 한 번에 여러 개의 테이블을 생성할 수 있다.
- 이미 존재하는 테이블은 무시되며, 존재하지 않는 테이블만 생성한다.
2) 사용법:
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL)
Base = declarative_base()
# 테이블 정의
from sqlalchemy import Column, Integer, String
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
# 테이블 생성
Base.metadata.create_all(bind=engine)
3) 특징:
- Base 클래스를 기반으로 모든 테이블을 한 번에 생성함
- 존재하는 테이블은 무시됨
- 초기 스키마 설정 시 사용
2. User.__table__.create(bind=engine)
1) 설명:
- 특정 테이블만 개별적으로 생성할 때 사용한다.
- Base.metadata.create_all()과 달리, 하나의 테이블만 생성할 수 있다.
- 테이블이 이미 존재하면 예외 발생한다. (sqlalchemy.exc.OperationalError)
2) 사용법:
# 특정 테이블만 생성
User.__table__.create(bind=engine)
3) 특징:
- 단일 테이블만 생성 가능
- 존재하는 테이블이면 예외 발생
- 특정 테이블만 개별적으로 생성할 때 유용
3. Base.metadata.tables['users'].create(bind=engine)
1) 설명:
- 특정 테이블을 Base.metadata.tables에서 가져와 생성할 수 있다.
- User.__table__.create(bind=engine)과 비슷하지만, 테이블명을 문자열로 접근할 수 있다.
2) 사용법:
# 특정 테이블 생성
Base.metadata.tables['users'].create(bind=engine)
3) 특징:
- 테이블 이름을 문자열로 다룰 수 있어 동적 테이블 생성이 가능
- 특정 테이블만 선택적으로 생성 가능
4. engine.execute(DDL("CREATE TABLE ..."))
1) 설명:
- DDL()을 사용하여 직접 SQL 쿼리를 실행할 수도 있다.
- 특정 테이블이 존재하는지 확인하고, 없으면 생성하는 방식으로 활용할 수 있다.
2) 사용법:
from sqlalchemy import text
from sqlalchemy.sql import DDL
# SQL 쿼리 직접 실행
engine.execute(DDL("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
)
"""))
3) 특징:
- SQL 쿼리를 직접 실행하므로, 더 세밀한 제어 가능
- 테이블 존재 여부를 직접 확인할 수 있음
- DBMS에 따라 다르게 작성해야 함 (MySQL, PostgreSQL 등)
5. Alembic을 사용한 마이그레이션 기반 생성
1) 설명:
- create_all()을 사용하면 기존 테이블을 변경할 수 없음 (마이그레이션 기능 없음)
- Alembic을 사용하면 버전 관리를 하면서 테이블을 변경하거나 추가할 수 있음
2) 사용법:
1.Alembic 초기화
alembic init alembic
2.alembic/versions/ 폴더에 마이그레이션 스크립트 생성
alembic revision --autogenerate -m "create users table"
3. 생성된 스크립트(alembic/versions/xxxx_create_users_table.py)를 수정한 후 적용
alembic upgrade head
3) 특징:
- create_all()과 달리 테이블 변경(ALTER TABLE) 가능
- 버전 관리가 가능하여 실무에서 필수적으로 사용됨
6. if not engine.dialect.has_table(engine, "users")
1) 설명:
- engine.dialect.has_table()을 사용하여 테이블이 존재하는지 확인한 후 생성할 수 있다.
- Base.metadata.create_all()을 호출하기 전에 특정 테이블이 있는지 검사할 때 유용하다.
2) 사용법:
from sqlalchemy.engine.reflection import Inspector
# 엔진을 통해 테이블 존재 여부 확인
if not engine.dialect.has_table(engine, "users"):
User.__table__.create(bind=engine)
3) 특징:
- 테이블 존재 여부를 직접 확인 가능
- 특정 테이블이 존재할 경우 중복 생성 방지 가능
7. 비교 정리
방법 | 특징 | 단일/전체 테이블 | 테이블 존재 시 동작 |
Base.metadata.create_all(bind=engine) | 모든 테이블 한 번에 생성 | 전체 테이블 | 존재하는 테이블 무시 |
User.__table__.create(bind=engine) | 특정 테이블만 생성 | 단일 테이블 | 존재 시 예외 발생 |
Base.metadata.tables['users'].create(bind=engine) | 특정 테이블만 생성 (문자열 접근) | 단일 테이블 | 존재 시 예외 발생 |
engine.execute(DDL("CREATE TABLE ...")) | 직접 SQL 실행 가능 | 단일 테이블 (직접 정의) | IF NOT EXISTS로 제어 가능 |
Alembic 마이그레이션 | 버전 관리 가능, 테이블 변경 가능 | 전체/단일 테이블 | 마이그레이션 방식 적용 |
engine.dialect.has_table(engine, "users") | 테이블 존재 여부 확인 후 생성 | 단일 테이블 | 존재 시 생성 안 함 |
8. 어떤 방법을 사용할까?
1) 초기 개발 단계
- Base.metadata.create_all(bind=engine) → 전체 테이블 생성
- User.__table__.create(bind=engine) → 개별 테이블만 필요할 때
2) 운영 및 유지보수 단계
- Alembic 마이그레이션 필수 (테이블 변경 관리 필요)
- 직접 SQL(engine.execute(DDL(...)))을 실행해야 하는 경우도 있음
3) 특정 테이블만 생성해야 할 때
- Base.metadata.tables['users'].create(bind=engine) 또는 User.__table__.create(bind=engine)
- 존재 여부 확인하려면 engine.dialect.has_table(engine, "users") 활용
'Study > fastapi' 카테고리의 다른 글
fastapi - G6 간단하게 훓어보기 - 1) 설치 (0) | 2025.02.19 |
---|---|
vscode, cusor ai에서 fastapi debug 하는 방법 with launch.json (0) | 2025.02.19 |
fastapi의 FastAPI() 메소드 사용법 정리 (0) | 2025.02.16 |
[udemy] Try FastAPI Test Driven Development 2024 - 학습 후기 (0) | 2025.02.15 |
[udemy] Try FastAPI Test Driven Development 2024 - 학습 정리 (0) | 2025.02.15 |
댓글