python - 从 sqlalchemy mixins 继承并添加索引

标签 python sql sqlalchemy

给定一个带有索引的 mixin,如何向继承该 mixin 的模型添加额外的索引?索引名称如 idx__TABLENAME__COLUMN mixin 无法获取自身的 TABLENAME。如果 __tablename__为 mixin 指定,则会出现重复的索引名称。

示例代码如下。

import sqlalchemy as sql
from sqlalchemy import Column, Index, String, Integer
from sqlalchemy.ext.declarative import declared_attr, declarative_base


Base = declarative_base()

class MixinOwner(object):
    id = Column('id', Integer, primary_key=True)
    owner = Column('owner', String)

    @declared_attr
    def __table_args__(cls):
        return (Index('idx__%s__owner' % cls.__tablename__, 'owner'), )


class Letter(MixinOwner, Base):
    __tablename__ = 'letter'
    a = Column('a', String)
    b = Column('b', String)

    @declared_attr
    def __table_args__(cls):
        mixin_indexes = list(MixinOwner.__table_args__)  # <--- Error (MixinOwner does not have attribute __tablename__)
        mixin_indexes.extend([
            Index('idx__letter__a', 'a'),
            Index('idx__letter__b', 'b'),
        ])
        return tuple(mixin_indexes)


class Word(MixinOwner, Base):
    __tablename__ = 'word'
    apple = Column('apple', String)
    banana = Column('banana', String)

    @declared_attr
    def __table_args__(cls):
        mixin_indexes = list(MixinOwner.__table_args__)
        mixin_indexes.extend([
            Index('idx__word__apple', 'apple'),
            Index('idx__word__banana', 'banana'),
        ])
        return tuple(mixin_indexes)




engine = sqlalchemy.create_engine('sqlite:///:memory:')
engine.connect()

Base.metadata.bind = engine
Base.metadata.create_all()

Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()

最佳答案

要合并 mixins 中的索引,您需要使用 super在子类的上下文中访问基类的方法。除了这个解决了我提出的原始问题的修复之外,还出现了另一个问题 - 如何合并来自多个 mixins 而不仅仅是一个的索引(如原始问题中的设置)。下面的代码也解释了这个更大的问题。解决方案是迭代 MRO 并获取 __table_args__对于具有模型上下文的每个基类。

import sqlalchemy as sql
from sqlalchemy import Column, Index, String, Integer, Date
from sqlalchemy.ext.declarative import declared_attr, declarative_base


Base = declarative_base()

class MixinOwner(object):
    id = Column('id', Integer, primary_key=True)
    owner = Column('owner', String)

    @declared_attr
    def __table_args__(cls):
        return (Index('idx__%s__owner' % cls.__tablename__, 'owner'), )

class MixinDate(object):
    date = Column('date', Date)

    @declared_attr
    def __table_args__(cls):
        return (Index('idx__%s__date' % cls.__tablename__, 'date'), )



# single mixin inheritance (original question) -- use super(cls, cls)
class Word(MixinOwner, Base):
    __tablename__ = 'word'
    apple = Column('apple', String)
    banana = Column('banana', String)

    @declared_attr
    def __table_args__(cls):
        mixin_indexes = list((super(cls, cls).__table_args__))
        mixin_indexes.extend([
            Index('idx__word__apple', 'apple'),
            Index('idx__word__banana', 'banana'),
        ])
        return tuple(mixin_indexes)


# multiple mixin iheritance (not in original question)
# iterate through __mro__ and aggregate __table_args__ from each base
class Letter(MixinOwner, MixinDate, Base):
    __tablename__ = 'letter'
    a = Column('a', String)
    b = Column('b', String)

    @declared_attr
    def __table_args__(cls):
        mixin_indexes = []
        for base_class in cls.__mro__:
            try:
                mixin_indexes.extend(super(base_class, cls).__table_args__)
            except AttributeError:
                pass
        mixin_indexes.extend([
            Index('idx__letter__a', 'a'),
            Index('idx__letter__b', 'b'),
        ])
        return tuple(mixin_indexes)




engine = sql.create_engine('sqlite:///:memory:')
engine.connect()

Base.metadata.bind = engine
Base.metadata.create_all()

Session = sql.orm.sessionmaker(bind=engine)
session = Session()

关于python - 从 sqlalchemy mixins 继承并添加索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47371450/

相关文章:

sqlalchemy group_by 和计数

python - 使用 python -c "command"设置 Docker ENV

Python:如何构建用于加载数据的文本文件?

python - 使用 Tweepy 的 Twitter 机器人 - Python

python - 在Python中将字符串日期解析为日期对象

mysql - SQL 计算多列和多行的特定值

mysql - 相关子查询更新

sql - 此平面文件结构需要 MySQL DDL,提供示例 : input columns, 数据、输出表/列等

python - 分配给未映射到 SQLAlchemy 列的属性时如何引发异常?

python - Sqlalchemy orm 根据给定输入动态查询过滤