Как я могу установить индекс для объявленного атрибута, используя декларативный ORM SQLAlchemy? - PullRequest
0 голосов
/ 16 октября 2018

Когда я пытаюсь определить индекс для объявленного атрибута

class Event(Base):

    @declared_attr
    def user_id(cls):
        return Column(BigInteger, ForeignKey("users.user_id"), nullable=False)

    idx_event_user_id = Index('idx_event_user_id', user_id)

, я получаю следующую ошибку:

sqlalchemy.exc.ArgumentError: Element <sqlalchemy.ext.declarative.api.declared_attr object at 0x1066ec648> is not a string name or column element

Есть ли другой способ сделать это?Могу ли я установить индексы для объявленного атрибута?

1 Ответ

0 голосов
/ 17 октября 2018

При работе с наследованием / миксинами вы должны передавать индексы, которые вы хотели бы создать для всех классов и их базовых Table, в качестве "встроенных" определений, используя __table_args__, который также должен быть объявленатрибут в этом случае, как описано в «Создание индексов с помощью миксинов» :

class Event(Base):

    @declared_attr
    def user_id(cls):
        return Column(BigInteger, ForeignKey("users.user_id"), nullable=False)

    @declared_attr
    def __table_args__(cls):
        # Return a tuple of arguments to pass to Table
        return (Index(f'idx_{cls.__tablename__}_user_id', 'user_id'),)

Это позволит избежать конфликтов имен между индексами, созданными для различных (под) классов.Обратите внимание, что здесь эта «встроенная» форма использует имена строк для идентификации столбцов для индексации, но cls.foo_id будет работать также и в объявленном атрибуте.В общем случае нет необходимости назначать Index в качестве атрибута модели, а в некоторых ситуациях это может даже привести к путанице .

Простое решение для индексациистолбец должен просто передать index=True в Column.Это ярлык для создания анонимного индекса для рассматриваемого столбца:

class Event(Base):

    @declared_attr
    def user_id(cls):
        return Column(BigInteger, ForeignKey("users.user_id"), nullable=False, index=True)

Если вы не имеете дело с наследованием / миксинами, вам не требуется перенос @declared_attr:

class MyModel(Base):
    foo = Column(Integer)
    bar = Column(Integer)

    # "Inline", but gets the actual column instead of a string name.
    # Possible with Declarative.
    __table_args__ = (Index('idx_mymodel_foo', foo),)

# Finds the table through the Column used in the definition.
Index('idx_mymodel_bar', MyModel.bar)

Причина, по которой вы получаете ошибку, заключается в том, что во время конструирования класса тело определения класса оценивается, а полученное пространство имен затем используется в качестве пространства имен класса.Во время этой оценки

idx_event_user_id = Index('idx_event_user_id', user_id)

приводит к Index получению объявленного атрибута дескриптор объекта, назначенного user_id в этом пространстве имен, как есть, и поэтому SQLAlchemy жалуется.

Когда вы обращаетесь к дескрипторам через созданный объект класса или его экземпляр, они начинают делать свое дело, что в случае объявленного атрибута означает, что оно оценивается как сопоставленное свойство или специальный декларативный член, который онпредставляет.

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