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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM