Как переопределить одноименные таблицы в SQLAlchemy с помощью классического сопоставления - PullRequest
2 голосов
/ 08 июля 2020

Я использую SQLAlchemy классическое сопоставление для определения таблицы с тем же именем, но разными столбцами в зависимости от db, я сопоставил класс, как это объясняется в документации, но я получаю ошибки каждый раз Я пытаюсь переопределить класс для другой базы данных. Например:

from sqlalchemy import (Table, MetaData, String, Column)
from sqlalchemy.orm import mapper


class MyTable(object):
    def __init__(self, *args, **kwargs):
        [setattr(self, k, v) for k, v in kwargs.items()]


default_cols = (
    Column('column1', String(20), primary_key=True),
    Column('column2', String(20))
)


def myfunc1():
    engine = create_engine('connection_to_database1')
    session = sessionmaker(bind=engine)()
    metadata = MetaData()
    mytable = Table('mytable', metadata, *default_cols)
    mapper(MyTable, mytable)
    metadata.create_all(bind=engine)

def myfunc2():
    engine = create_engine('connection_to_database2')
    session = sessionmaker(bind=engine)()
    metadata = MetaData()
    columns =  list(default_cols) + [Column('column3', String(20))]
    mytable = Table('mytable', metadata, *columns)
    mapper(MyTable, mytable)
    metadata.create_all(bind=engine)


myfunc1()
myfunc2()

Я получаю ошибку:

Column object 'column1' already assigned to Table 'mytable'

Как это происходит, если я использую совершенно разные экземпляры MetaData и движков? Есть ли способ добиться этого?

Ответы [ 2 ]

1 голос
/ 08 июля 2020

Я не смог воспроизвести вашу ошибку. Чтобы код заработал, мне пришлось поменять местами аргументы Mapper и добавить первичные ключи в определения таблиц. Что еще более важно, мне пришлось установить один из сопоставителей как неосновной после получения этой ошибки:

sqlalchemy.exc.ArgumentError: Class '<class '__main__.MyTable'>' already has a primary
mapper defined. Use non_primary=True to create a non primary Mapper.  clear_mappers() 
will remove *all* current mappers from all classes.
from sqlalchemy import Table, MetaData, String, Column, create_engine, Integer
from sqlalchemy.orm import mapper


class MyTable(object):
    def __init__(self, *args, **kwargs):
        [setattr(self, k, v) for k, v in kwargs.items()]
        
        
def myfunc1():
    engine = create_engine("mysql+pymysql:///test")
    metadata = MetaData() 
    mytable = Table(
        "mytable111",
        metadata,
        Column("id", Integer, primary_key=True),
        Column("column1", String(20)),
        Column("column2", String(20)),
    )
    mapper(MyTable, mytable)
    metadata.create_all(bind=engine)
        
        
def myfunc2():
    engine = create_engine("postgresql+psycopg2:///test")
    metadata = MetaData() 
    mytable = Table(
        "mytable111",
        metadata,
        Column("id", Integer, primary_key=True),
        Column("column1", String(20)),
        Column("column2", String(20)),
        Column("column3", String(20)),
    )
    mapper(MyTable, mytable, non_primary=True)
    metadata.create_all(bind=engine)


myfunc1()
myfunc2()

Используя Python3 .8, SQLAlchemy 1.3.10.

0 голосов
/ 11 июля 2020

Использование переменной default_cols на самом деле было проблемой, похоже, такая настройка не работает, если столбцы не определены индивидуально для каждой функции:


def myfunc1():
    engine = create_engine('connection_to_database1')
    session = sessionmaker(bind=engine)()
    metadata = MetaData()
    mytable = Table('mytable', metadata, 
        Column('column1', String(20), primary_key=True),
        Column('column2', String(20))
    )
    mapper(MyTable, mytable)
    metadata.create_all(bind=engine)

def myfunc2():
    engine = create_engine('connection_to_database2')
    session = sessionmaker(bind=engine)()
    metadata = MetaData()
    columns =  [
        Column('column1', String(20), primary_key=True),
        Column('column2', String(20),
        Column('column3', String(20))
    ]
    mytable = Table('mytable', metadata, *columns)
    mapper(MyTable, mytable)
    metadata.create_all(bind=engine)

В противном случае это будет вызвать исключение:

Column object 'column1' already assigned to Table 'mytable'

...