我们创建ORM的基类的目的除了提供公共字段和属性外,还可以实现更高级的功能。
以上是我们一个应用示例,Post有一个entries皇粮指向不同的entry,在上述代码中我们直接使用relationship来跟Entry创建一个一对多的关系,
但上述代码会出错,出错的原因是因为Entry是一个抽象基类,在数据库中并没有创建对应的数据库表,所以不能创建一对多关系。
在stackoverflow上发现一个应用案例,在此转载一下。
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))
以上Entry是一个基类,没有对应的数据库表,TextEntry和PhotoEntry均继承自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)
entries = db.relationship(Entry, lazy="dynamic")
以上是我们一个应用示例,Post有一个entries皇粮指向不同的entry,在上述代码中我们直接使用relationship来跟Entry创建一个一对多的关系,
理想情况应该是post的entries可以包含不同的Entry,如
>>Post.entries.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>]
但上述代码会出错,出错的原因是因为Entry是一个抽象基类,在数据库中并没有创建对应的数据库表,所以不能创建一对多关系。
幸运的是AbstractConcreteBase提供了__delcare_last__
可以用来解决这些问题,代码如下:
class Post(db.Model):
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)