sqlalchemy 2.0 에서는 다음과 같이 한다.
# model.py
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class SchemaMixin:
date: Mapped[str] = mapped_column(Date)
open: Mapped[int]
...
class MyTable(Base, SchemaMixin):
__tablename__ = 'mytable'
예를 들어, SchemaMixin 의 schema를 가지는 두 table인 MyTable1, MyTable2 을 생성한다고 하면, 위의 예제와 마찬가지로 다음과 같이 하면 된다.
#model.py
class MyTable1(Base, SchemaMixin):
__tablename__ = 'mytable1'
class MyTable2(Base, SchemaMixin):
__tablename__ = 'mytable2'
그런데 이걸 두 개가 아니라 1000개쯤 만들어야한다면? 😨
다음과 같이 하면 쉽게 동적으로 만들 수 있다.
#model.py
from sqlalchemy import create_engine
mytable1 = type('MyTable1', (Base, SchemaMixin), {'__tablename__': 'mytable1'})
mytable2 = type('MyTable2', (Base, SchemaMixin), {'__tablename__': 'mytable2'})
...
Base.metadata.create_all(engine)
그런데 이렇게하면 alembic 에서 revision --autogenerate 를 실행하면 schema를 찾을 수 없다고 에러를 뿌린다. 말 그대로 '동적'이니 해당 코드를 실제로 실행하고 지나가지 않으면 alembic에서는 모를 수도 있겠구나 싶었다.
다뤄야 할 table 개수가 수천개 정도로 매우 많기 때문에 table을 만들 때부터 alembic을 사용하기로 결정. (이건 잘한 선택인듯)
다음과 같이 정적인 python code 를 하나의 파일로 생성하도록 만들었다.
import random
import string
def genTables(outFileName: str):
cpCodeMgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")
targets = [''.join(random.choices(string.ascii_letters, k=9) for _ in range(1000)]
schemaMixin = 'SchemaMixin'
header = '''
from sqlalchemy.orm import DeclarativeBase
from .model import {schemaMixin}
'''
body = '''
class Base(DeclarativeBase):
pass
'''
classTemplate = '''
class {symbol}(Base, {schemaMixin}):
__tablename__ = '{target}'
'''
with open(outFileName, 'w') as f:
f.write(header.format(schemaMixin=schemaMixin))
f.write(body)
for t in targets:
f.write(classTemplate.format(target=t, schemaMixin=schemaMixin))
이걸 수행하면 python file이 하나 만들어지고(예를 들어, model/tables.py), alembic의 env.py 에서는 만들어진 python 파일을 metadata 경로에 써주면 된다.
#env.py inside alembic directory
...
#sys.path.insert(0, os.getcwd())
from src.model import Base
target_metadata = Base.metadata
...
이렇게 하면 table 개수가 몇 개가 됐든 상관없이 alembic을 이용해 --autogenerate feature도 쓸 수 있어 편해짐.