• Flask中数据库的多对多关系


    大多数的其他关系类型都可以从一对多类型中衍生。多对一关系从“多”的一次看,就是一对多关系。一对一关系是简化版的一对多关系。唯一不能从一对多关系中演化出来的类型就是多对多关系。

    • 多对多关系

    一对多,多对一,一对一关系至少都有一侧是单个实体,表之间的联系通过外键实现,让外键指向那个实体。解决多对多的关系,需要引入第三张表,称为关联表,由此可以分解成原表和关联表之间的两个一对多关系。 比如学生选课,一个学生可以选择多门课程,一门课程可以被多个学生选择,这是一个典型的多对多的关系。

    多对多关系在查询时的流程:比如查找一个学生选了哪些课程,首先从学生和注册之间的一对多关系开始,获取学生student_id对应的所有class_id,然后在按照多对一的方向遍历课程和注册之间的一对多的关系,找到该学生选择的所有课程。

    1. 两个实体多对多关系

      Flask-SQLAlchemy实现多对多关系

     1 registrations = db.Table('registrations', 
     2     db.Column('student_id', db.Integer, db.ForeignKey('students.id')),
     3     db.Column('class_id', db.Integer, db.ForeignKey('classes.id')))
     4 
     5 class Student(db.Model):
     6     __tablename__ = 'students'
     7     id = db.Column(db.Integer, primary_key=True)
     8     name = db.Column(db.String)
     9     classes = db.relationship('Class', secondary=registrations,
    10                               backref = db.backref('students', lazy='dynamic'),
    11                               lazy='dynamic')
    12 
    13 class Class(db.Model):
    14     __tablename__ = 'classes'
    15     id = db.Column(db.Integer, primary_key=True)
    16     name = db.Column(db.String)

    在多对多关系中,依然使用db.relationship()方法定义,但在多对多关系中,必须把secondary参数设为关联表。多对多关系可以在任何类中定义,backref参数会处理好关系的另一侧。关联表就是一个简单的表,不是模型,Flask-SQLAlchemy会自动接管这个表。

    学生注册课程:

    1 stu.classes.append(c)
    2 db.session.add(stu)

    列出学生注册的所有课程:

    1 stu.classes.all()

    注册了课程c的所有学生:

    1 c.students.all()
    • 自引用关系

    在用户关注功能中,多对多关系中并不存在两个实体,只有User一个实体模型。如果关系中的两侧都在同一个表中,这种关系称为自引用关系

    关联表follows,其中每一行表示一个用户关注另一个用户。左侧表示follower,可理解为粉丝,右侧表示followed,可理解为关注别人。

    使用多对多关系时,需要存储两个实体之间的额外信息,比如某个用户关注另一个用户的时间信息。为了能处理自定义的数据,可以将关联表设计成可访问的模型。

     1 class Follow(db.Model):
     2     __tablename__ = 'follows'
     3     follower_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
     4     followed_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
     5     timestamp = db.Column(db.DateTime, default=datetime.utcnow)
     6     
     7 class User(UserMixin, db.Model):
     8     __tablename__ = 'users'
     9     ...
    10     followers = db.relationship('Follow',
    11                                foreign_keys=[Follow.followed_id],
    12                                backref=db.backref('followed', lazy='joined'),
    13                                lazy='dynamic',
    14                                cascade='all, delete-orphan')
    15     followed = db.relationship('Follow',
    16                                foreign_keys=[Follow.follower_id],
    17                                backref=db.backref('follower', lazy='joined'),
    18                                lazy='dynamic',
    19                                cascade='all, delete-orphan')

    参数介绍:

      1. foreign_keys参数表示关联的外键

      2. backref参数表示将followed/follower回引Follow模型, 可以通过Follow.follower访问粉丝,通过Follow.followed访问关注的人

      3. 回引中的lazy参数指定为joined可以实现立即从联结查询中加载相关对象

      4. cascade参数配置在父对象上执行的操作对相关对象的影响

    • 关注关系的辅助方法

     1 class User(UserMixin, db.Model):
     2     __tablename__ = 'users'
     3     ...
     4     
     5     # 关注某个用户
     6     def follow(self, user):
     7         # 判断是否已经关注了
     8         if not self.is_following(user):
     9             # 新建关联表对象实例,记录粉丝和被关注者的关系
    10             f = Follow(follower=self, followed=user)
    11             db.session.add(f)
    12     
    13     # 取消关注某个用户
    14     def unfollow(self, user):
    15         # 检查取消的关注的用户是否已经被关注了
    16         f = self.followed.filter_by(followed_id=user.id).first()
    17         if f:
    18             db.session.delete(f)
    19     
    20     # 判断是否已经关注
    21     def is_following(self, user):
    22         # 确认用户有没有id,以防创建了用户,但是未提交到数据库
    23         if user.id is None:
    24             return False
    25         return self.followed.filter_by(followed_id=user.id).first() is not None
    26     
    27     # 判断是否被关注
    28     def is_followed_by(self, user):
    29         if user.id is None:
    30             return False
    31         return self.followers.filter_by(follower_id=user.id).first() is not None
    • END

  • 相关阅读:
    WebClient, HttpClient, HttpWebRequest ,RestSharp之间的区别与抉择(几种Http请求方法)
    关于c#里面的httpclient的调用
    mvc项目架构分享系列之架构搭建初步 架构搭建初步
    关于在.NET中 DAL+IDAL+Model+BLL+Web
    三层架构(DAL/BLL/UI)和MVC设计模式的关系
    c#开发初学者之mvc及架构分层
    c#串口编程(转)
    【WPF】对话框/消息弹窗
    WPF如何不显示最大化,最小化的按钮
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1103:陶陶摘苹果
  • 原文地址:https://www.cnblogs.com/toomax/p/12972169.html
Copyright © 2020-2023  润新知