назначение определенного столбца первичным ключом при отражении существующей таблицы с sqlalchemy и turbogears - PullRequest
1 голос
/ 19 ноября 2011

это часть проекта, который включает в себя работу с tg2 против двух баз данных, одна из которых (эта модель использует mssql). Поскольку эта таблица, из которой мне нужно читать / писать, создается и управляется с помощью другого приложения, я не хочу, чтобы турбогенераторы перезаписывали / меняли таблицу - просто работайте с существующей таблицей - поэтому я использую магическое отражение автозагрузки sqlalchemy (я также не знаю всех деталей конфигурации этой таблицы в базе данных mssql) часть отражения сделана в model.__init__.py, а не в классе (как подсказывают некоторые учебники по sqlalchemy) из-за внутренней работы tg2

это сообщение об ошибке, которое я получаю: (имя таблицы в db SOMETABLE, а в моем приложении класс деятельности)

sqlalchemy.exc.ArgumentError: Mapper Mapper|Activities|SOMETABLE could not
 assemble any primary key columns for mapped table 'SOMETABLE'

это класс занятий:

class Activities(DeclarativeBase2):

    __tablename__ = 'SOMETABLE'
    #tried the classic way, I used in another place without tg but didn't work here -      the reflection should be outside the class
    #__table_args__=  {'autoload':True
                      #,'autoload_with':engine2
                     #}
    def __init__(self,**kw):
        for k,v in kw.items():
            setattr(self,k,v)

и это model.__init__.py метод модели init (где вызывается отражение):

def init_model(engine1,engine2):
    """Call me before using any of the tables or classes in the model."""
    DBSession.configure(bind=engine1)
    DBSession2.configure(bind=engine2)

    # If you are using reflection to introspect your database and create
    # table objects for you, your tables must be defined and mapped inside
    # the init_model function, so that the engine is available if you
    # use the model outside tg2, you need to make sure this is called before
    # you use the model.

    #
    # See the following example:
    metadata.bind = engine1
    metadata2.bind = engine2
    #metadata2=MetaData(engine2)

    global t_reflected
    #
    t_reflected = Table("SOMETABLE", metadata2,
        autoload=True, autoload_with=engine2)
    #
    mapper(Activities, t_reflected

поэтому я думаю, что мне нужно сообщить sqlalchemy, что является первичным ключом - но как мне это сделать, используя отражение (я знаю поле первичного ключа)?

РЕДАКТИРОВАТЬ рабочий раствор :

def init_model(engine1,engine2):
    """Call me before using any of the tables or classes in the model."""
    DBSession.configure(bind=engine1)
    DBSession2.configure(bind=engine2)

    # If you are using reflection to introspect your database and create
    # table objects for you, your tables must be defined and mapped inside
    # the init_model function, so that the engine is available if you
    # use the model outside tg2, you need to make sure this is called before
    # you use the model.

    #
    # See the following example:
    metadata.bind = engine1
    metadata2.bind = engine2
    #metadata2=MetaData(engine2)

    global t_reflected
    #
    t_reflected = Table("SOMETABLE", metadata2,String,primary_key=True),
        autoload=True, autoload_with=engine2)# adding the primary key column here didn't work
    #
    mapper(Activities, t_reflected, non_primary=True)# notice the needed non_primary - for some reason I can't do the whole mapping in one file and I Have to do part in init_model and part in the model - quite annoying

также в модели мне пришлось добавить столбец первичного ключа, сделав его:

class Activities(DeclarativeBase2):

__tablename__ = 'SOMETABLE'
#tried the classic way, I used in another place without tg but didn't work here -      the reflection should be outside the class
EVENTCODE = Column(String, primary_key=True)# needed because the reflection couldn't find the primary key .

конечно, мне также пришлось добавить различные импорта в model.__init__.py, чтобы сделать эту работу

Странно то, что выяснилось, что он жаловался на то, что не нашел первичный ключ до того, как он даже подключился к БД, и когда автономный класс sqlalchemy (без tg2) делал тот же ключ - вообще не жаловался. заставляет задуматься

1 Ответ

1 голос
/ 21 ноября 2011

Вы можете смешивать и сочетать: см. Переопределение отраженных столбцов в документации.В вашем случае код будет выглядеть примерно так:

t_reflected = Table("SOMETABLE", metadata2,
    Column('id', Integer, primary_key=True), # override reflected '???' column to have primary key
    autoload=True, autoload_with=engine2)

edit-1: Версия модели: Я также считаю, что должна работать только декларативная версия, и в этом случае вам следуетне определять таблицу t_reflected, а также не должен отображать таблицы вручную, используя mapper(...), поскольку декларативные классы автоматически отображаются:

class Activities(DeclarativeBase2):
    __table__ = Table('SOMETABLE', metadata2,
        Column('EVENTCODE', Unicode, primary_key=True),
        autoload=True, autoload_with=engine2,
    )
    def __init__(self,**kw):
        for k,v in kw.items():
            setattr(self,k,v)
...