您好我正在尝试使用sqlalchemy将遗留应用程序移植到python。
应用程序的现有数据库有大约300个表,每个表中都有一个名为def的列,如:
create table accnt (
code varchar(20)
, def varchar(50) --for accnt definition
, ...
)
因此,当使用声明性语法和反射时,我可以轻松地创建我的类:
class Accnt(Base):
__table__ = Table('accnt', metadata, autoload = True, autoload_with=engine)
但是当我尝试访问 def 列时,我最终会收到错误消息。例如:
q = session.query(Accnt)
for row in q:
print q.def
因为 def 是python的保留字:(
为了克服这个问题,我可以创建我的课程:
class Accnt(Base):
__table__ = Table('accnt', metadata, autoload = True, autoload_with=engine)
__mapper_args__ = {'column_prefix':'_'}
但是在每个列名前放一个_是无聊的,而不是花哨的。
我想要做的是使用其他名称/(密钥?)访问def列。
有什么想法吗?
---编辑--- (根据TokenMacGuy的要求编辑原始帖子)
虽然我接受了TokenMacGuy的答案,但我之前尝试过:
engine = create_engine('firebird://sysdba:masterkey@127.0.0.1/d:\\prj\\db2\\makki.fdb?charset=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))
而且我有 sqlalchemy.exc.ArgumentError:指定表时无法添加其他列'def' 误差..
我和TokenMacGuy之间的主要区别是
mine : _table_ ....
TokenMcGuy : __tablename__ = 'accnt'
__table_args__ = {'autoload': True}
和元数据绑定......
那么,为什么我之前的尝试产生错误?
答案 0 :(得分:13)
你也可以吃蛋糕。定义要重命名的列; 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>
>>>
编辑:
通过提供__table__
参数,您告诉声明性扩展,您已经拥有了一个您想要使用的正确配置的Table
。但事实并非如此;您希望在类中使用另一个名称引用def
列。通过使用__tablename__
和__table_args__
,您可以推迟表的构造,直到您告诉声明如何使用该表为止。如果您已经开始使用__table__
,那么就没有优雅的解决方法。您可以提供对列进行别名的property
,也可以将列指定为_def = getattr(__table__.c, 'def')
。
真的,你应该只使用__tablename__
;它既方便又灵活,这就是原因的一个很好的例子。
(顺便说一句,最常见的是为备用标识符提供尾随下划线而不是前导下划线,使用def_
代替_def
;引导下划线通常表示该名称为“私有”或'一个实现细节',如果名称是公开的,但看起来像一个私人名称,它可能会导致更多的混乱)
答案 1 :(得分:3)
您可以这样定义您的表:
mymetadata = MetaData()
Base = declarative_base(metadata=mymetadata)
class Accnt(Base):
__tablename__ = 'accnt'
code = Column(String(20))
def_ = Column(String(50))
答案 2 :(得分:0)
这可能过于蛮力,但另一种方法是使用sqlacodegen
库为您的数据库自动生成所有模型,然后手动更改这些模型,或调整sqlacodegen
来构建使用您的约定的模型。它支持将保留字映射到其他符号。