SQLAlchemy与具体继承的多态关系

时间:2012-02-10 06:22:54

标签: python orm sqlalchemy flask-sqlalchemy concrete-inheritance

我正在使用SQLAlchemy的具体表继承。在声明样式模型类中,我已成功配置它。

我的代码就像:

class Entry(AbstractConcreteBase, db.Model):
    """Base Class of Entry."""

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    created = db.Column(db.DateTime, nullable=False)
    post_id = declared_attr(lambda c: db.Column(db.ForeignKey("post.id")))
    post = declared_attr(lambda c: db.relationship("Post", lazy="joined"))

    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    @declared_attr
    def __mapper_args__(cls):
        # configurate subclasses about concrete table inheritance
        return {'polymorphic_identity': cls.__name__,
                'concrete': True} if cls.__name__ != "Entry" else {}

class TextEntry(Entry):
    """Text and Article Entry."""

    text = db.deferred(db.Column(db.Text, nullable=False))

class PhotoEntry(Entry):
    """Photo Entry."""

    path = db.deferred(db.Column(db.String(256), nullable=False))

在shell中测试它时工作正常:

>>> from models.entry import Entry
>>>
>>> Entry.query.all()
[<PhotoEntry 'Title' created by tonyseek>,
 <PhotoEntry 'TITLE 2' created by tonyseek>,
 <PhotoEntry 'Title 3' created by tonyseek>,
 <PhotoEntry 'Title 4' created by tonyseek>,
 <TextEntry 'Title' created by tonyseek>]

然后我在其他模型中设置关系时陷入困境。每个条目都有一个外键post_id来加入Post模型,但我无法在Post中定义后向引用。这不起作用:

class Post(db.Model):
    """An Post."""

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    description = db.Column(db.Unicode(140), nullable=False)
    entries = db.relationship(Entry, lazy="dynamic")

它提出了一个例外并说:

  

InvalidRequestError:一个或多个映射器无法初始化 - 无法继续初始化其他映射器。原始异常是:类'models.entry.Entry'未映射。

显然Entry是一个抽象类,无法映射到真实存在的表。官方网站上的文档有一个例子,但它的基类不是抽象的。现在我该如何设置与抽象模型的多态关系?

1 个答案:

答案 0 :(得分:7)

我找到了问题的原因及其解决方案。

根据sqlalchemy官方网站的文档,抽象类可以是映射类,因为polymorphic_union函数可以创建虚拟表。

我正在使用声明样式模型,而不是手动构建映射器,因此不应手动创建虚拟表pjoin。基类AbstractConcreteBase有一个方法__delcare_last__会创建pjoin polymorphic_union函数,但会在事件after_configured触发时调用。

在生成Entry类之后,Post中与Post的关系将被创建,此时事件after_configured尚未被触发,因此{{1}函数尚未创建虚拟表__delcare_last__并将其映射到pjoin。因此,未映射“类'models.entry.Entry'的异常。”将被提出。

现在,我重构Entry模型,让它在Post函数中创建与Entry的关系,然后由于触发事件和映射{{1 }}

我新实现的类如下:

__delcare_last__