【问题标题】:How to override a column name in sqlalchemy using reflection and descriptive syntax如何使用反射和描述性语法覆盖 sqlalchemy 中的列名
【发布时间】:2011-12-02 13:17:42
【问题描述】:

您好,我正在尝试使用 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?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))

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

我和TokenMacGuy的主要区别是

mine       : _table_ ....
TokenMcGuy : __tablename__ = 'accnt'
             __table_args__ = {'autoload': True}

和元数据绑定...

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

【问题讨论】:

  • 因为您将班级设置为使用您已经制作的表格,而不是让您的班级从您的属性中自动生成它。设置 table 后无法创建更多列
  • @jdi 在 TokenMacGuy 的解释之后,您的评论更有意义。但我认为你们俩都在说同样的话,而 TMG 解释得更多:)

标签: python sqlalchemy


【解决方案1】:

你也可以吃蛋糕。定义要重命名的列; 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;前导下划线通常表示名称是“私有”或“实现细节” ',如果该名称是公开的,但看起来像一个私有名称,则可能会引起不必要的混乱)

【讨论】:

  • 谢谢!我尝试使用以下代码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: Can't add Additional column 'def' when指定 table' 错误...这两种方法有什么区别?
  • @ctengiz - 我认为这是因为您这样做的方式已经生成了表格。如果要为列指定不同的命名属性,则需要内联。
  • 请在原始问题中发布您的代码;当你把它放在评论中时,几乎不可能理解它。
  • 在你回答之前,我找到了一个肮脏的解决方案:Accnt.defi = getattr(Accnt, 'def') 这既不优雅也不像pythonic,可能会导致其他问题..
【解决方案2】:

你可以这样定义你的表:

mymetadata = MetaData()
Base = declarative_base(metadata=mymetadata)

class Accnt(Base):
    __tablename__ = 'accnt'

    code = Column(String(20))
    def_ = Column(String(50))

【讨论】:

  • 我知道,但我想使用反射。没有反射这将是大量的编码。因为我试图访问的数据库是一个包含许多表的现有数据库......
  • TokenMacGuy 做了几乎相同的事情,但有更好的例子和清晰度:-)
【解决方案3】:

这可能太暴力了,但另一种方法是使用 sqlacodegen 库为您的数据库自动生成所有模型,然后手动更改这些模型,或者调整 sqlacodegen 以使用您的约定构建模型.它支持将保留字映射到其他符号。

https://pypi.python.org/pypi/sqlacodegen。不错的工具。

【讨论】:

    猜你喜欢
    • 2012-08-31
    • 1970-01-01
    • 2014-11-21
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多