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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酬姆,隨后出現(xiàn)的幾起案子嗜桌,更是在濱河造成了極大的恐慌,老刑警劉巖辞色,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骨宠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡相满,警方通過查閱死者的電腦和手機(jī)层亿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來立美,“玉大人匿又,你說我怎么就攤上這事〗ㄌ悖” “怎么了碌更?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)洞慎。 經(jīng)常有香客問我痛单,道長(zhǎng),這世上最難降的妖魔是什么劲腿? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任旭绒,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘快压。我一直安慰自己圆仔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布蔫劣。 她就那樣靜靜地躺著坪郭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脉幢。 梳的紋絲不亂的頭發(fā)上歪沃,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音嫌松,去河邊找鬼沪曙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛萎羔,可吹牛的內(nèi)容都是我干的液走。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贾陷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缘眶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起髓废,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巷懈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后慌洪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顶燕,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年冈爹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涌攻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犯助,死狀恐怖癣漆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剂买,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布癌蓖,位于F島的核電站瞬哼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏租副。R本人自食惡果不足惜坐慰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望用僧。 院中可真熱鬧结胀,春花似錦赞咙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至秸抚,卻和暖如春速和,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剥汤。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工颠放, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吭敢。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓碰凶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鹿驼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痒留,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容