При работе с наследованием / миксинами вы должны передавать индексы, которые вы хотели бы создать для всех классов и их базовых 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 жалуется.
Когда вы обращаетесь к дескрипторам через созданный объект класса или его экземпляр, они начинают делать свое дело, что в случае объявленного атрибута означает, что оно оценивается как сопоставленное свойство или специальный декларативный член, который онпредставляет.