동일한 Schema를 가지는 복수 개의 table 생성하기

ddoachi·2024년 12월 8일

mixin을 이용한 table 생성 방법

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'

class 를 동적으로 생성

Naive 한 방법

예를 들어, SchemaMixin 의 schema를 가지는 두 table인 MyTable1, MyTable2 을 생성한다고 하면, 위의 예제와 마찬가지로 다음과 같이 하면 된다.

#model.py

class MyTable1(Base, SchemaMixin):
	__tablename__ = 'mytable1'

class MyTable2(Base, SchemaMixin):
	__tablename__ = 'mytable2'

그런데 이걸 두 개가 아니라 1000개쯤 만들어야한다면? 😨

Metaclass의 사용

다음과 같이 하면 쉽게 동적으로 만들 수 있다.

#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에서는 모를 수도 있겠구나 싶었다.

template 을 사용해 python schema 파일 생성

다뤄야 할 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), alembicenv.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도 쓸 수 있어 편해짐.

profile
내일도 풀스택

0개의 댓글