在使用sqlalchemy和turbogears反映现有表时,将特定列指定为主键

时间:2011-11-19 16:10:05

标签: sqlalchemy turbogears2

这是一个项目的一部分,涉及使用tg2对抗2个数据库中的一个(该模型使用的是mssql)。因为我需要读/写的表是用不同的应用程序创建和管理的,所以我不希望turbogears覆盖/更改表 - 只需使用现有的表 - 所以我使用sqlalchemy神奇的'autoload'反射(我也是不知道mssql db中这个表配置的每个细节) 一些反思是在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 个答案:

答案 0 :(得分:1)

您可以混合搭配:请参阅文档中的Overriding Reflected Columns。在您的情况下,代码看起来类似于:

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)