使用连接表继承时,Mixin将添加到每个子类表中

时间:2011-10-06 05:04:07

标签: python sqlalchemy pyramid

我有以下设置:

class Attribute(object):
    a = Column(Integer)

class Thing(Base, Attribute):
    b = Column(Integer)

class Subthing(Thing):
    c = COlumn(Integer)

但是,Thing和Subthing都有属性mixin,这意味着它们都有属性中指定的列:

Thing: a | b
Subthing: a | c

我只希望这些mixin列出现在Thing而不是Subthing:

Thing: a | b
Subthing: c

这是可能的还是我必须手动制作列和方法,而不是每次使用mixin?

3 个答案:

答案 0 :(得分:4)

Subthing通过继承定义从父级获取a。如果您不想要该行为,则Subthing无法从该对象继承。一种可能的解决方案是引入另一个基类。

class Attribute(object):
    @declared_attr # the actual syntax on SQLAlchemy for doing mixins
    def a(cls):
       return Column(Integer)

class BaseThing(Base):
    pass

class Thing(BaseThing, Attribute):
    b = Column(Integer)

class Subthing(BaseThing):
    c = Column(Integer)

然后,Subthing只有c列,而Thing有ab

答案 1 :(得分:1)

这是一种行为不一致,它是由于@declared_attr的行为慢慢偏离仅针对“列复制”用例进行测试的行为合同而产生的。 “mixin上的列”的原始用例是将它同等地应用于所有继承类,但是稍后开发的@declared_attr没有采用这种行为,因此不一致。

将“列副本”更改为仅对非子类生效是向后兼容的行为更改,因此仅在即将到来的0.8中。这是机票#2565(http://www.sqlalchemy.org/trac/ticket/2565),已在r9baa197f2c67中解决。

试验:

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

class Mixin(object):
    a = Column(Integer)

    @declared_attr
    def b(cls):
        return Column(Integer)

class A(Mixin, Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)

class B(A):
    __tablename__ = 'b'
    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

assert 'a' in A.__table__.c
assert 'b' in A.__table__.c
assert 'a' not in B.__table__.c
assert 'b' not in B.__table__.c

答案 2 :(得分:0)

我刚遇到同样的问题。事实证明,如果使用@declared_attr在mixin类中定义列,则SQLAlchemy行为正常。直接在mixin中声明的列在使用连接表继承时会泄漏到子类中。