给定一个带索引的mixin,如何向继承该mixin的模型添加其他索引?使用像idx__TABLENAME__COLUMN
这样的索引名称,mixin无法为自己获取TABLENAME。如果为mixin指定了__tablename__
,则会出现重复的索引名称。
示例代码如下。
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()
答案 0 :(得分:0)
要合并mixins中的索引,您需要使用super
来访问子类上下文中的基类方法。除了这个解决我提出的原始问题的解决方案之外,还有另一个问题 - 如何合并来自多个mixin的索引而不仅仅是一个(如原始问题中的设置)。以下代码也解释了这个更大的问题。解决方案是迭代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()