上篇文章學(xué)習(xí)了Flask框架——模型關(guān)系(一對多關(guān)系),這篇文章我們學(xué)習(xí)Flask框架——模型關(guān)系(多對多關(guān)系)。
我們拿學(xué)生和課程為例子,一個學(xué)生可以選多門課程,一門課程可以被多名學(xué)生選,所以它們是多對多關(guān)系,我們假設(shè)數(shù)據(jù)庫中學(xué)生表與課程表如下圖所示:
如何使這兩張表建立聯(lián)系呢,是在課程表中多加一個字段來表示哪個學(xué)生選了這門課嗎?
假如是在課程表中多加一個字段,每門課只能被一個學(xué)生選,那么該怎么辦好呢?
想要兩張表建立聯(lián)系,多加一個字段不行的話,那么我們多建一張表不就好了嗎?如下圖所示:
通過創(chuàng)建第三張表來使學(xué)生表與課程表建立關(guān)系,第三張表我們稱為關(guān)系表,數(shù)據(jù)庫是這樣設(shè)計,那么如何使模型之間產(chǎn)生聯(lián)系呢,如何編寫模型之間產(chǎn)生聯(lián)系的代碼呢?
在編寫模型類代碼之前,首先我們創(chuàng)建一個Flask項目,其目錄如下所示:
創(chuàng)建好項目后,我們開始編寫配置文件settings.py的代碼,如下所示:
class Configs:
ENV='development'
DEBUG=True
# 設(shè)置連接數(shù)據(jù)庫路徑
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@127.0.0.1:3306/test'
# 每次請求結(jié)束后自動提交數(shù)據(jù)庫中的改動
SQLALCHEMY_COMMIT_ON_TEARDOWN=True
# 禁用SQLAlchemy對追蹤對象的修改并且發(fā)送信號
SQLALCHEMY_TRACK_MODIFICATIONS = False
編寫好配置文件后,我們將配置文件導(dǎo)入app.py文件中,代碼如所示:
from flask import Flask
from settings import Config
app = Flask(__name__)
app.config.from_object(Config) # 加載配置
編寫模型類
好了,F(xiàn)lask框架的基礎(chǔ)配置已經(jīng)寫好了,接下來我們在app.py文件中編寫學(xué)生模型類與課程模型類,代碼如下所示:
from flask_sqlalchemy import SQLAlchemy
# 創(chuàng)建映射對象db
db=SQLAlchemy(app=app,use_native_unicode="utf8")
#Student模型類
class Student(db.Model):
__tablename__ = 'student' # 數(shù)據(jù)表名
id=db.Column(db.Integer,primary_key=True) #學(xué)生id
name=db.Column(db.String(20),nullable=False) #學(xué)生名
password=db.Column(db.Integer,nullable=False) #密碼
#Course模型類
class Course(db.Model):
__tablename__='course' #數(shù)據(jù)表名
id=db.Column(db.Integer,primary_key=True) #課程id
course_name=db.Column(db.String(50),nullable=False) #課程名
credit=db.Column(db.Float,nullable=False) #學(xué)分
students = db.relationship('Student', backref='course', secondary='student_course') #設(shè)置studens字段,使Course模型類與Student模型類產(chǎn)生聯(lián)系
這里我們在Course模型類中添加了students字段,該字段使用了db.relationship()方法讓Course模型與Student模型產(chǎn)生了聯(lián)系,當(dāng)然也可以在Student模型類中添加course字段并使用db.relationship()方法使Student模型與Course模型產(chǎn)生聯(lián)系,在Student模型類添加字段代碼如下所示:
course = db.relationship('Course', backref='student', secondary='student_course')
其中:
- 'Course'參數(shù)是你要產(chǎn)生聯(lián)系的模型類;
- backref是反向引用,其值可以是任意字符,該字符很重要,可以調(diào)用關(guān)聯(lián)模型類的屬性字段;
- secondary的值是關(guān)系數(shù)據(jù)表的表名。
注意:db.relationship()方法只能在兩個相關(guān)聯(lián)的模型類中任意選擇一個調(diào)用,也就是說只能在Course模型類或者Student模型類中調(diào)用。
好了,學(xué)生模型類和課程模型類已經(jīng)寫好了,不知道你們有沒有發(fā)現(xiàn),學(xué)生模型與課程模型都沒有設(shè)置外鍵的代碼,這是因為外鍵要設(shè)置在關(guān)系數(shù)據(jù)表中,接下來編寫關(guān)系數(shù)據(jù)表的模型類代碼,代碼如下所示:
#第三張數(shù)據(jù)表模型類
class Student_Course(db.Model):
__tablename__='student_course' #數(shù)據(jù)表名
id=db.Column(db.Integer,primary_key=True) #id
student_id=db.Column(db.Integer,db.ForeignKey('student.id')) #學(xué)生id
course_id=db.Column(db.Integer,db.ForeignKey('course.id')) #課程id
當(dāng)還有其他模型類要關(guān)聯(lián)時,只要在上面的模型類添加外鍵字段即可。
除了這樣設(shè)置關(guān)系數(shù)據(jù)表外,我們還可以通過db.Table()方法來設(shè)置,代碼如下所示:
tags=db.Table('student_course', #數(shù)據(jù)表名
db.Column('id',db.Integer,primary_key=True) #id
db.Column('student_id',db.Integer,db.ForeignKey('student.id')), #學(xué)生id
db.Column('course_id',db.Integer,db.ForeignKey('course.id')) #課程id
)
其中:student_id為數(shù)據(jù)表的字段,db.Integer為字段的數(shù)據(jù)類型,這里是整型,db.ForeignKey()方法傳遞的是模型類.模型類主鍵。
好了,模型類代碼已經(jīng)寫好了,接下來我們通過在app.py中編寫代碼創(chuàng)建數(shù)據(jù)表,其代碼如下所示:
if __name__ == '__main__':
db.create_all() #創(chuàng)建數(shù)據(jù)表
app.run()
在終端執(zhí)行app.py后,就成功創(chuàng)建好數(shù)據(jù)表了,下面我們在pycharm中看看這三張表的聯(lián)系,如下圖所示:
這樣就成功把student數(shù)據(jù)表與course數(shù)據(jù)表聯(lián)系起來了,我們手動為這三張表添加數(shù)據(jù),如下圖所示:
接下來我們將通過學(xué)生來找出該學(xué)生選的課程和通過課程來找出該課程被哪些學(xué)生。
通過學(xué)生找課程
首先編寫視圖函數(shù),代碼如下所示:
@app.route('/findcourse')
def course():
student_id=request.args.get('id') #獲取學(xué)生id
student=Student.query.get(student_id) #獲取學(xué)生數(shù)據(jù)
return render_template('course.html',student=student) #通過render_template()方法將course.html完整地呈現(xiàn)在網(wǎng)頁中,并傳遞student學(xué)生數(shù)據(jù)到網(wǎng)頁中
編寫好視圖函數(shù)后,接下來在templates文件夾中創(chuàng)建一個名為course的html文件,其代碼如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>學(xué)生找已選課程</title>
</head>
<body>
學(xué)生名:{{ student.name }}
<br>
該學(xué)生選了以下課程:
{% for course in student.course %}
<p>{{ course.course_name }}---{{ course.credit }}學(xué)分</p>
{% endfor %}
</body>
</html>
第八行代碼,我們將傳遞過來的student中獲取學(xué)生名,在第十一行代碼中,我們利用Course模型類中的反向引用backref參數(shù)值course,通過student.course就可以獲取課程對象,通過課程對象來獲取課程名、課程學(xué)分。在終端執(zhí)行app.py,并在瀏覽器中打開http://127.0.0.1:5000/findcourse?id=2022001,如下圖所示:
這里我們找了學(xué)號為2022001,其選了Python程序設(shè)計、數(shù)據(jù)分析、數(shù)據(jù)可視化。
通過課程找學(xué)生
首先編寫視圖函數(shù),代碼如下所示:
@app.route('/findstudent')
def student():
course_id=request.args.get('id') #獲取課程id
courses=Course.query.get(course_id) #獲取課程數(shù)據(jù)
return render_template('student.html',courses=courses) #通過render_template()方法將student.html完整地呈現(xiàn)在網(wǎng)頁中,并傳遞courses學(xué)生數(shù)據(jù)到網(wǎng)頁中
編寫好視圖函數(shù)后,接下來在templates文件夾中創(chuàng)建一個名為student的html文件,其代碼如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通過課程找學(xué)生</title>
</head>
<body>
課程名:{{ courses.course_name }}
<br>
選擇該課程的學(xué)生有:
{% for student in courses.students %}
<p>{{ student.name }}---學(xué)號:{{ student.id }}</p>
{% endfor %}
</body>
</html>
第八行代碼,通過傳遞的courses數(shù)據(jù)獲取課程名,第十一行代碼,使用了Course模型類中students字段,通過courses.students獲取到了學(xué)生對象,再通過學(xué)生對象獲取學(xué)生名、學(xué)號。
在終端執(zhí)行app.py,并在瀏覽器中打開http://127.0.0.1:5000/findstudent?id=003,如下圖所示:
這里我們獲取課程id為003,其學(xué)生有張三,學(xué)號為2022001。
通過關(guān)系數(shù)據(jù)表使另外兩張數(shù)據(jù)表產(chǎn)生了聯(lián)系,并可以互相獲取到數(shù)據(jù)。
好了,F(xiàn)lask框架——模型關(guān)系(多對多關(guān)系)就講到這里了,下篇文章繼續(xù)學(xué)習(xí)Flask框架——Session與Cookie,感謝觀看?。?!
公眾號:白巧克力LIN