理解SQLAlchemy的表继承关系(4)--高级应用

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)

 

posted on 2020-04-08 13:58  不要挡着我晒太阳  阅读(323)  评论(0编辑  收藏  举报

导航