上篇文章學(xué)習(xí)了Flask框架——模型關(guān)系(一對(duì)多關(guān)系),這篇文章我們學(xué)習(xí)Flask框架——模型關(guān)系(多對(duì)多關(guān)系)出牧。
我們拿學(xué)生和課程為例子悴了,一個(gè)學(xué)生可以選多門課程,一門課程可以被多名學(xué)生選刀疙,所以它們是多對(duì)多關(guān)系舶赔,我們假設(shè)數(shù)據(jù)庫(kù)中學(xué)生表與課程表如下圖所示:
如何使這兩張表建立聯(lián)系呢,是在課程表中多加一個(gè)字段來表示哪個(gè)學(xué)生選了這門課嗎谦秧?
假如是在課程表中多加一個(gè)字段竟纳,每門課只能被一個(gè)學(xué)生選撵溃,那么該怎么辦好呢?
想要兩張表建立聯(lián)系锥累,多加一個(gè)字段不行的話征懈,那么我們多建一張表不就好了嗎?如下圖所示:
通過創(chuàng)建第三張表來使學(xué)生表與課程表建立關(guān)系揩悄,第三張表我們稱為關(guān)系表卖哎,數(shù)據(jù)庫(kù)是這樣設(shè)計(jì),那么如何使模型之間產(chǎn)生聯(lián)系呢删性,如何編寫模型之間產(chǎn)生聯(lián)系的代碼呢亏娜?
在編寫模型類代碼之前,首先我們創(chuàng)建一個(gè)Flask項(xiàng)目蹬挺,其目錄如下所示:
創(chuàng)建好項(xiàng)目后维贺,我們開始編寫配置文件settings.py的代碼,如下所示:
class Configs:
ENV='development'
DEBUG=True
# 設(shè)置連接數(shù)據(jù)庫(kù)路徑
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@127.0.0.1:3306/test'
# 每次請(qǐng)求結(jié)束后自動(dòng)提交數(shù)據(jù)庫(kù)中的改動(dòng)
SQLALCHEMY_COMMIT_ON_TEARDOWN=True
# 禁用SQLAlchemy對(duì)追蹤對(duì)象的修改并且發(fā)送信號(hào)
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)寫好了榕茧,接下來我們?cè)赼pp.py文件中編寫學(xué)生模型類與課程模型類垃沦,代碼如下所示:
from flask_sqlalchemy import SQLAlchemy
# 創(chuàng)建映射對(duì)象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)系
這里我們?cè)贑ourse模型類中添加了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()方法只能在兩個(gè)相關(guān)聯(lián)的模型類中任意選擇一個(gè)調(diào)用血崭,也就是說只能在Course模型類或者Student模型類中調(diào)用卧惜。
好了,學(xué)生模型類和課程模型類已經(jīng)寫好了功氨,不知道你們有沒有發(fā)現(xiàn)序苏,學(xué)生模型與課程模型都沒有設(shè)置外鍵的代碼,這是因?yàn)橥怄I要設(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í),只要在上面的模型類添加外鍵字段即可跺涤。
除了這樣設(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ù)表了再榄,下面我們?cè)趐ycharm中看看這三張表的聯(lián)系,如下圖所示:
這樣就成功把student數(shù)據(jù)表與course數(shù)據(jù)表聯(lián)系起來了享潜,我們手動(dòng)為這三張表添加數(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)頁(yè)中疾就,并傳遞student學(xué)生數(shù)據(jù)到網(wǎng)頁(yè)中
編寫好視圖函數(shù)后,接下來在templates文件夾中創(chuàng)建一個(gè)名為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就可以獲取課程對(duì)象侮攀,通過課程對(duì)象來獲取課程名锣枝、課程學(xué)分。在終端執(zhí)行app.py兰英,并在瀏覽器中打開http://127.0.0.1:5000/findcourse?id=2022001撇叁,如下圖所示:
這里我們找了學(xué)號(hào)為2022001,其選了Python程序設(shè)計(jì)畦贸、數(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)頁(yè)中趋厉,并傳遞courses學(xué)生數(shù)據(jù)到網(wǎng)頁(yè)中
編寫好視圖函數(shù)后,接下來在templates文件夾中創(chuàng)建一個(gè)名為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é)號(hào):{{ student.id }}</p>
{% endfor %}
</body>
</html>
第八行代碼君账,通過傳遞的courses數(shù)據(jù)獲取課程名,第十一行代碼沈善,使用了Course模型類中students字段乡数,通過courses.students獲取到了學(xué)生對(duì)象椭蹄,再通過學(xué)生對(duì)象獲取學(xué)生名、學(xué)號(hào)净赴。
在終端執(zhí)行app.py绳矩,并在瀏覽器中打開http://127.0.0.1:5000/findstudent?id=003,如下圖所示:
這里我們獲取課程id為003玖翅,其學(xué)生有張三翼馆,學(xué)號(hào)為2022001。
通過關(guān)系數(shù)據(jù)表使另外兩張數(shù)據(jù)表產(chǎn)生了聯(lián)系金度,并可以互相獲取到數(shù)據(jù)写妥。
好了,F(xiàn)lask框架——模型關(guān)系(多對(duì)多關(guān)系)就講到這里了审姓,下篇文章繼續(xù)學(xué)習(xí)Flask框架——Session與Cookie珍特,感謝觀看!D隆扎筒!
公眾號(hào):白巧克力LIN