12.1 高级多对多关系

一. 一对多关系

    我们前面讲了两个一对多关系:角色和它所对应的用户, 用户和它所对应的文章, 在一对多关系中, 我们在‘一’的这边设置db.relationship, 在‘多’的一边设置一个外键。

二. 多对多关系

    而数据库除了一对多关系之外还有多对多关系。最常见的是学生选课这个多对多关系, 一个学生可以选择多门课程, 一门课程也可以被多个学生选择, 如果我们在学生这边添加外键显然行不通, 因为一个学生可以选择多门课程, 在课程这边添加外键同理也行不通。那我们如何解决?

    我们可以建立一张关系表, 用两个一对多关系表示多对多关系:

   

                                一      ————————》                多                 《———————       一

   一个学生对应多个选课记录, 从而查找到这个学生选择的多门课程;

   一门课程也对应多个选课记录, 从而查找到选这门课程的多个学生。

三. 自引用多对多关系

    1.概念:

    用户之间的相互关注就是一个多对多关系, 关注者可以关注多个被关注者, 被关注者也可以被多个关注者关注, 这里的关注者和被关注者都是用户, 两端是同一个实体, 不像学生选课, 两端是不同实体。 这就是自引用多对多关系。

   

2. 实现:

class Follow(db.Model):

    __tablename__ = 'follows'

    follower_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)

    followed_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)

    timestamp = (db.Datetime, default=datetime.utcnow)

 

class User(UserMixin, db.Model):

    followed = db.relationship('Follow',

                                                foreign_keys=[Follow.follower_id],

                                                backref=db.backref('follower', lazy='joined'),

                                                cascade='all, delete-orphan')

    followers = db.relationship('Follow',

                                                 foreign_keys=[Follow.followed_id],

                                                 backref=db.backref('followed', lazy='joined'),

                                                 cascade='all, delete-orphan')

3. 代码解释

    上述代码使用两个一对多关系表示了多对多关系。


我们先回想一下用户和文章这个一对多关系,以便于我们理解用户之间的多对多关系:

class User(db.Model):

    posts = db.relationship('Post', backref='author', lazy='dynamic')


class Post(db.Model):

    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))

我们在‘一’这边的user模型中添加了一个posts属性, 用户实例调用posts会得到该用户的所有文章组成的列表, 并且用backref参数为post实例添加了author属性, 文章实例调用author属性时会得到它对应的用户。

我们在‘多’这边的Post模型中添加了author_id外键。

下面来讲解用户之间的多对多关系:

    假设当前用户是关注者, 我们要在用户模型中添加一个属性followed, 用户调用followed会得到他所有的被关注者, 只不过这里是Follow实例组成的列表, 然后我们为Follow实例添加一个follower属性, Follow实例调用follower属性时得到关注者实例。并在‘多’这边添加follower_id外键。

    假设当前用户是被关注者, 我们要在用户模型中添加一个属性followers, 用户调用该属性会的到他所有关注者, 只不过这里是Follow实例组成的列表, 然后我们为这些Follow实例添加一个followed属性, 调用得到被关注者实例。 并在‘多’这边添加followed_id外键。

    backref=''joined'作用是减少数据库查询的次数。

    cascade=‘all, delete-orphan’参数的作用是当删除用户时, 删除其对应的Follow实例, 而不是只把Follow记录中与其相关的外键设为空。

4.关注关系的辅助方法

class User(db.Model):

    def follow(self, user): #关注user
        if not self.is_following(user):
            f = Follow(follower=self, followed=user)
            db.session.add(f)

    def unfollow(self, user): #取关user
        f = self.followed.filter_by(followed_id=user.id).first()
        if f:
            db.session.delete(f)

    def is_following(self, user): #判断是否关注user
        return self.followed.filter_by(followed_id==user.id).first

    def is_followed_by(self, user):  #判断是否被user关注
        return self.followers.filter_by(follower_id=user.id).first()






   

猜你喜欢

转载自blog.csdn.net/sinat_34927324/article/details/80039035