Как переопределить имя столбца в sqlalchemy с помощью отражения и описательного синтаксиса

Привет я пытаюсь перенести устаревшее приложение на python с помощью sqlalchemy.

существующая база данных приложения имеет около 300 таблиц, и в каждой таблице есть colum с именем 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:prjdb2makki.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.экскавация.ArgumentError: не удается добавить дополнительный столбец "def" при указании таблицы ошибка..

основное различие между мной и TokenMacGuy является

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

и привязки метаданных...

Итак, почему моя предыдущая попытка сгенерировала ошибку ?

3 ответов


вы можете иметь ваш торт и съесть его. Определите столбцы, которые вы хотите переименовать; 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>
>>> 

EDIT:

, предоставив __table__ аргумент, вы говорите декларативному расширению, что у вас уже есть правильно настроенный Table что вы хотели бы использовать. Но это не так; вы хотите иметь def столбец, на который ссылается другое имя в классе. Используя __tablename__ и __table_args__, вы откладываете построение таблицы до тех пор, пока не скажете декларативно, как вы хотите использовать эту таблицу. Там нет элегантной работы вокруг, если вы dead set на использование __table__. Вы можете предоставить property это псевдонимы столбца или вы можете указать столбец как _def = getattr(__table__.c, 'def').

на самом деле, вы должны просто использовать __tablename__; это более удобно и более гибко, и это отличный пример того, почему.

(кстати, это самые обычные давать альтернативные идентификаторы конечное подчеркивание вместо ведущего подчеркивания используйте def_ вместо _def; ведущие подчеркивания обычно означают, что имя является "частным" или "детализацией реализации", если имя должно быть общедоступным, но выглядит как частное имя, это может вызвать больше путаницы, чем необходимо)


вы можете определить свою таблицу следующим образом:

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

class Accnt(Base):
    __tablename__ = 'accnt'

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

Это может быть слишком много грубой силы, но другой подход заключается в использовании sqlacodegen библиотека для автоматического создания всех моделей для вашей БД, а затем изменить их вручную, или настроить sqlacodegen чтобы построить модели, используя ваши соглашения. Он поддерживает сопоставление зарезервированных слов с другими символами.

см.https://pypi.python.org/pypi/sqlacodegen. Хороший инструмент.