如何使用反射和描述性语法覆盖sqlalchemy中的列名

cte*_*giz 10 python sqlalchemy

您好我正在尝试使用sqlalchemy将遗留应用程序移植到python.

应用程序的现有数据库有大约300个表,每个表中都有一个名为def的列,如:

create table accnt (
    code varchar(20)
  , def varchar(50) --for accnt definition
  , ...
)
Run Code Online (Sandbox Code Playgroud)

因此,当使用声明性语法和反射时,我可以轻松地创建我的类:

class Accnt(Base):
    __table__ = Table('accnt', metadata, autoload = True, autoload_with=engine)
Run Code Online (Sandbox Code Playgroud)

但是当我试图达到def列时,我最终得到一个错误.例如 :

q = session.query(Accnt)
for row in q:
    print q.def
Run Code Online (Sandbox Code Playgroud)

因为def是python的保留字:(

要克服这个问题,我可以创建我的课程:

class Accnt(Base):
    __table__ = Table('accnt', metadata, autoload = True, autoload_with=engine)
    __mapper_args__ = {'column_prefix':'_'}
Run Code Online (Sandbox Code Playgroud)

但是在每个列名前放一个_是无聊的,而不是花哨的.

我想要做的是访问def列与另一个名称/(键?).

有任何想法吗?

---编辑---(根据TokenMacGuy的要求编辑原帖)

虽然我已经接受了TokenMacGuy的回答,但我之前尝试过:

engine = create_engine('firebird://sysdba:masterkey@127.0.0.1/d:\\prj\\db2\\makki.fdb?charse??t=WIN1254', echo=False) 
metadata = MetaData() 
DbSession = sessionmaker(bind=engine) 
Base = declarative_base() 

class Accnt(Base):
    __table__ = Table('accnt', metadata, autoload = True, autoload_with=engine) 
    _def = Column("def", String(50))
Run Code Online (Sandbox Code Playgroud)

我有sqlalchemy.exc.ArgumentError:指定表错误时无法添加额外的列'def'.

我和TokenMacGuy之间的主要区别是

mine       : _table_ ....
TokenMcGuy : __tablename__ = 'accnt'
             __table_args__ = {'autoload': True}
Run Code Online (Sandbox Code Playgroud)

和元数据绑定......

那么,为什么我以前的尝试产生错误?

Sin*_*ion 15

你可以吃蛋糕,也可以吃.定义要重命名的列; sqlalchemy将自动推断您未提及的任何列.

>>> from sqlalchemy import *
>>> from sqlalchemy.ext.declarative import declarative_base
>>> 
>>> engine = create_engine("sqlite:///:memory:")
>>> 
>>> engine.execute("""
... create table accnt (
...     id integer primary key,
...     code varchar(20),
...     def varchar(50)
... )
... """)
<sqlalchemy.engine.base.ResultProxy object at 0x2122750>
>>> 
>>> Base = declarative_base()
>>> 
>>> Base.metadata.bind = engine
>>> 
>>> class Accnt(Base):
...     __tablename__ = 'accnt'
...     __table_args__ = {'autoload': True}
...     def_ = Column('def', String)
... 
>>> Accnt.def_
<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x2122e90>
>>> Accnt.code
<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x2127090>
>>> 
Run Code Online (Sandbox Code Playgroud)

编辑:

通过提供__table__参数,您告诉声明性扩展,您已经有一个Table您想要使用的正确配置.但事实并非如此; 您希望def在类中使用另一个名称引用该列.通过使用__tablename____table_args__,你推迟表的构造,直到你告诉声明如何使用该表.如果您已经无法使用,那么就没有优雅的解决方法__table__.您可以为property列提供别名,或者您可以将列指定为_def = getattr(__table__.c, 'def').

真的,你应该使用__tablename__; 它既方便又灵活,这就是原因的一个很好的例子.

(顺便说一句,最常见的是给备用标识符一个尾随下划线而不是前导下划线,def_而不是使用_def;前导下划线通常表示名称是'私有'或'实现细节',如果名称是公共,但看起来像一个私人名称,它可能会导致比必要更多的混乱)