【问题标题】:How can I set an index on a declared attribute using SQLAlchemy Declarative ORM?如何使用 SQLAlchemy 声明性 ORM 在声明的属性上设置索引?
【发布时间】:2018-10-16 11:02:33
【问题描述】:

当我尝试在声明的属性上定义索引时

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

还有其他方法可以做到这一点吗?我可以在声明的属性上设置索引吗?

【问题讨论】:

  • 您是否使用Event 作为继承层次结构中的基类,如果是,子类是否不会索引user_id
  • 感谢您的提问! event 是继承层次结构中的基类,user_id 应该是所有子类中的索引。但是,有时我也需要外键作为索引,没有继承。你是说每个都有不同的解决方案吗?

标签: python sqlalchemy


【解决方案1】:

在处理继承/混合时,您应该使用__table_args__ 将您希望为所有类及其底层Table 创建的索引作为“内联”定义传递,在这种情况下它也应该是一个声明的属性,如在"Creating Indexes with 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 指定为模型属性,在某些情况下也不需要指定it may even lead to confusion

索引列的简单解决方案是将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 的声明属性descriptor 对象,因此SQLAlchemy 抱怨。

当您通过构造的类对象或它的实例访问描述符时,它们会做自己的事情,在declared attribute 的情况下,这意味着它会评估映射属性或它所代表的特殊声明性成员。

【讨论】:

  • 感谢您的精心回复!对于已声明属性(例如外键)上的非 Mixin 索引,解决方案是相同的,没有名称冲突的预防措施?即:``` class SpecificEvent(Base): @declared_attr def user_id(cls): return Column(BigInteger, ForeignKey("users.user_id"), nullable=False) @declared_attr def __table_args__(cls): # 返回一个元组传递给表的参数返回 (Index('idx_specific_event_user_id', 'user_id'),)```
  • 嗯,我不是 100% 肯定我会跟随。如果你没有在继承层次结构中创建 Mixin、ABC 或基类,则不需要使用声明的属性,也不需要注意事项。
  • TL;DR:如果有可能基于代码创建多个索引,则需要一个鉴别器。
猜你喜欢
  • 2011-10-01
  • 2012-11-03
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多