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

1

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

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

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

  • 0
    Используете ли вы Event в качестве базового класса в иерархии наследования, и если да, то не будут ли подклассы индексировать user_id ?
  • 0
    Спасибо за ваш вопрос! Событие - это базовый класс в иерархии наследования, а user_id должен быть индексом во всех дочерних классах. Однако в других случаях мне нужны внешние ключи как индексы, где нет наследования. Вы говорите, что для каждого есть свое решение?
Теги:
sqlalchemy

1 ответ

0
Лучший ответ

При работе с наследованием /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 жалуется.

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

  • 0
    Спасибо за ваш сложный ответ! Для не-Mixin-индекса для Decla_attribute (например, внешнего ключа), решение то же самое, без мер предосторожности для конфликтов имен? Т.е.: `` `class SpecificEvent (Base): @declared_attr def user_id (cls): возвращать столбец (BigInteger, ForeignKey (" users.user_id "), nullable = False) @declared_attr def __table_args __ (cls): # возвращать кортеж из аргументы для передачи в таблицу возвращаются (Index ('idx_specific_event_user_id', 'user_id'),) `` `
  • 0
    Хм, я не уверен на 100%, что я следую. Если вы не создаете Mixin, ABC или базовый класс в иерархии наследования, вам не нужно использовать объявленные атрибуты, и нет необходимости в мерах предосторожности.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню