Flask框架——模型關(guān)系(多對多)

上篇文章學(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容