Jia*_*ang 5 python orm sqlalchemy concrete-inheritance flask-sqlalchemy
我正在使用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))
Run Code Online (Sandbox Code Playgroud)
它在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>]
Run Code Online (Sandbox Code Playgroud)
然后我在其他模型中设置关系时陷入困境.每个条目都有一个外键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")
Run Code Online (Sandbox Code Playgroud)
它提出了一个例外并说:
InvalidRequestError:一个或多个映射器无法初始化 - 无法继续初始化其他映射器.原始异常是:类'models.entry.Entry'未映射.
显然Entry是一个抽象类,无法映射到真正存在的表.官方网站上的文档有一个例子,但它的基类不是抽象的.现在我该如何设置与抽象模型的多态关系?
我找到了问题的原因及其解决方案.
根据sqlalchemy官方网站的文档,抽象类可以是映射类,因为该polymorphic_union函数可以创建虚拟表.
我正在使用声明样式模型,而不是手动构建映射器,因此pjoin不应手动创建虚拟表.基类AbstractConcreteBase有一个方法__delcare_last__可以创建pjoinwith polymorphic_union函数,但它会在事件after_configured触发时被调用.
Entry在生成类Post之后将创建与in 的关系,Post此时事件after_configured尚未被触发,因此__delcare_last__函数尚未创建虚拟表pjoin并将其映射到Entry.因此,未映射"类'models.entry.Entry'的异常." 将被提出.
现在,我重构Post模型,让它Entry在__delcare_last__函数中创建关系,然后由于触发事件和映射而成功Entry.
我新实现的类是这样的:
class Post(db.Model):
"""An Post."""
id = db.Column(db.Integer, primary_key=True, nullable=False)
description = db.Column(db.Unicode(140), nullable=False)
@classmethod
def __declare_last__(cls):
cls.entries = db.relationship(Entry, viewonly=True)
def attach_entries(self, entries):
"""Attach Entries To This Post.
Example:
>>> post = Post("An Interesting News", "Wow !!!")
>>> text_entry = TextEntry(*t_args)
>>> photo_entry = PhotoEntry(*p_args)
>>> post.attach_entries([text_entry, photo_entry])
>>> len(post.entries)
2
>>> db.session.commit()
>>>
"""
for entry in entries:
self.entries.append(entry)
entry.post = self
db.session.add(entry)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3208 次 |
| 最近记录: |