Как переопределить имя столбца в sqlalchemy, используя рефлексию и описательный синтаксис - PullRequest
7 голосов
/ 07 октября 2011

Здравствуйте. Я пытаюсь перенести устаревшее приложение на python с помощью sqlalchemy.

Существующая база данных приложения содержит около 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}

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

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

Ответы [ 3 ]

13 голосов
/ 07 октября 2011

Ты можешь взять свой пирог и съесть его тоже. Определите столбцы, которые вы хотите переименовать; 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; начальные подчеркивания обычно означают, что имя является «частным» или «деталь реализации» ', если имя предназначено для публичного использования, но выглядит как личное имя, это может вызвать больше путаницы, чем необходимо)

3 голосов
/ 07 октября 2011

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

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

class Accnt(Base):
    __tablename__ = 'accnt'

    code = Column(String(20))
    def_ = Column(String(50))
0 голосов
/ 26 сентября 2016

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...