Когда я пытаюсь определить индекс по объявленному атрибуту
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
Есть ли другой способ сделать это? Могу ли я индексировать объявленный атрибут?
При работе с наследованием /mixins вы должны передавать индексы, которые вы хотели бы создать для всех классов и их базовую Table
как "встроенные" определения, используя __table_args__
, который также должен быть объявленным атрибутом в этом случае, как описано в "Создание индексов с помощью Mixins ":
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)
Когда вы не имеете дело с наследованием /mixins, вам не нужно обертывать @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 жалуется.
Когда вы обращаетесь к дескрипторам через построенный объект класса или экземпляр его, они получают возможность выполнить свою задачу, которая в случае объявленного атрибута означает, что он оценивает сопоставленное свойство или специальный декларативный элемент, который он представляет.
Event
в качестве базового класса в иерархии наследования, и если да, то не будут ли подклассы индексироватьuser_id
?