每篇前言:
????作者介紹:【孤寒者】—CSDN全棧領(lǐng)域優(yōu)質(zhì)創(chuàng)作者、HDZ核心組成員、華為云享專家Python全棧領(lǐng)域博主、CSDN原力計(jì)劃作者
- ????本文已收錄于Flask框架從入門到實(shí)戰(zhàn)專欄:《Flask框架從入門到實(shí)戰(zhàn)》
- ????熱門專欄推薦:《Python全棧系列教程》、《爬蟲從入門到精通系列教程》、《爬蟲進(jìn)階+實(shí)戰(zhàn)系列教程》、《Scrapy框架從入門到實(shí)戰(zhàn)》、《Flask框架從入門到實(shí)戰(zhàn)》、《Django框架從入門到實(shí)戰(zhàn)》、《Tornado框架從入門到實(shí)戰(zhàn)》、《前端系列教程》。
- ?????本專欄面向廣大程序猿,為的是大家都做到Python全棧技術(shù)從入門到精通,穿插有很多實(shí)戰(zhàn)優(yōu)化點(diǎn)。
- ????訂閱專欄后可私聊進(jìn)一千多人Python全棧交流群(手把手教學(xué),問題解答); 進(jìn)群可領(lǐng)取Python全棧教程視頻 + 多得數(shù)不過來的計(jì)算機(jī)書籍:基礎(chǔ)、Web、爬蟲、數(shù)據(jù)分析、可視化、機(jī)器學(xué)習(xí)、深度學(xué)習(xí)、人工智能、算法、面試題等。
- ????加入我一起學(xué)習(xí)進(jìn)步,一個(gè)人可以走的很快,一群人才能走的更遠(yuǎn)!
![]()
MTV&MVC
先來講一下兩種常見的軟件架構(gòu)模式——MTV和MVC~
它倆是用于組織和管理應(yīng)用程序的不同組件和邏輯。通常用于開發(fā)Web應(yīng)用程序和其他軟件項(xiàng)目。
- MTV(Model-Template-View):
- Model(模型):表示應(yīng)用程序的數(shù)據(jù)和業(yè)務(wù)邏輯。它負(fù)責(zé)管理數(shù)據(jù)的存儲(chǔ)、檢索和處理,以及處理與數(shù)據(jù)相關(guān)的操作。
- Template(模板):定義了應(yīng)用程序用戶界面的外觀和結(jié)構(gòu),通常使用模板語言編寫,將動(dòng)態(tài)數(shù)據(jù)插入靜態(tài)頁面中。
- View(視圖):表示用戶界面的邏輯部分,它從模型中獲取數(shù)據(jù)并將其呈現(xiàn)到模板中,然后將結(jié)果發(fā)送給用戶的瀏覽器。視圖還可以處理用戶的輸入和用戶界面的交互。
MTV模式是Django Web框架的一部分(但是這個(gè)模式也非常適合Flask),其中Model對(duì)應(yīng)于數(shù)據(jù)模型,Template對(duì)應(yīng)于模板文件,View對(duì)應(yīng)于視圖函數(shù),這些組合在一起用于構(gòu)建Web應(yīng)用程序。
- MVC(Model-View-Controller):
- Model(模型):與MTV中的模型類似,負(fù)責(zé)應(yīng)用程序的數(shù)據(jù)和業(yè)務(wù)邏輯。它處理數(shù)據(jù)的存儲(chǔ)、檢索和處理。
- View(視圖):與MTV中的視圖有些不同,它表示應(yīng)用程序的用戶界面,但不直接與模板相關(guān)。視圖接收用戶輸入,處理它并與模型進(jìn)行通信以更新數(shù)據(jù)。
- Controller(控制器):控制器是MVC的核心,它負(fù)責(zé)接收用戶輸入并根據(jù)輸入調(diào)度視圖和模型的操作。它決定如何響應(yīng)用戶的請(qǐng)求,并確保模型和視圖之間的協(xié)同工作。
MVC模式通常在框架如Spring、Ruby on Rails等中使用,它的核心思想是分離數(shù)據(jù)處理、用戶界面和控制流,以提高代碼的可維護(hù)性和可擴(kuò)展性。控制器充當(dāng)用戶輸入的處理中心,調(diào)度模型和視圖以完成所需的操作。
總的來說,MTV和MVC都是用于組織和管理應(yīng)用程序代碼的模式,它們有不同的實(shí)現(xiàn)方式,但目標(biāo)都是分離關(guān)注點(diǎn),以提高代碼的可讀性和可維護(hù)性。
一一對(duì)應(yīng):
Flask如果采用MVC架構(gòu)的話,項(xiàng)目結(jié)構(gòu)demo:
但是推薦在Flask中使用MTV架構(gòu)模式,而且Flask中主流也是用這個(gè):
構(gòu)建一個(gè)基于MTV模式的Demo項(xiàng)目:
-
login.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用戶登錄</title> </head> <body> <form action="" method="post"> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交">{{msg}} </form> </body> </html>
-
account.py:
from flask import Blueprint, render_template, request, session, redirect from uuid import uuid4 account = Blueprint('account', __name__) @account.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'GuHanZhe' and pwd == '123': uid = str(uuid4()) session['user_info'] = {'id': uid, 'name': user} return redirect('/index') else: return render_template('login.html', msg='用戶名獲或密碼錯(cuò)誤')
-
home.py:
from flask import Blueprint, session home = Blueprint('home', __name__) @home.route('/index') def index(): user_info = session.get('user_info') print(user_info) return 'Index' @home.route('/test') def test(): return 'Test'
-
__init__.py
:from flask import Flask from .views import account from .views import home def create_app(): app = Flask(__name__) app.config.from_object('settings.DevelopmentConfig') app.register_blueprint(account.account) app.register_blueprint(home.home) return app
-
manage.py:
from flask_stru import create_app app = create_app() if __name__ == '__main__': app.run()
-
settings.py:
class Config(object): DEBUG = True SECRET_KEY = 'GuHanZheIsCool' class ProductionConfig(Config): pass class DevelopmentConfig(Config): pass class TestingConfig(Config): pass
運(yùn)行manage.py文件,訪問login登錄(登錄成功的話):
來看下源碼,看看默認(rèn)cookie過期時(shí)間是多久:
from flask.sessions import SecureCookieSessionInterface
可以看到注釋中表示這個(gè)值默認(rèn)是31天~而且我們可以設(shè)置這個(gè)值:
而這個(gè)參數(shù)生效的前提是session.permanent為True(默認(rèn)就是為True);
如果設(shè)置為False,則關(guān)閉瀏覽器cookie就失效。
再看看源碼設(shè)置cookie的(save_session)上面這一部分:
如果if成立就直接返回,客戶端就不會(huì)存cookie了!
蹦出一個(gè)問題:
訪問index接口是正常的,name修改成功:
但是如果訪問test接口的話,就不正常了:
很容易想到,這個(gè)問題的原因是因?yàn)閏ookie修改后沒有保存!
拋出答案,這是因?yàn)樾薷腸ookie的話,默認(rèn)只有當(dāng)?shù)谝粚有薷牟艜?huì)保存,而第二層、第三層等…都不會(huì)保存。
{
user_info: {k1: 1, k2: 2}
}
如果是第一層被修改會(huì)保存:
{
user_info: {k1: 1, k2: 2},
xxx :{'A': 5}
}
但是如果是第二層,第三層...修改不會(huì)保存:
{
user_info: {k1: 1, k2: 2, k3: 3}
}
看源碼分析這種問題的點(diǎn)源于何處:
斗膽翻譯一下第一個(gè)箭頭所指變量對(duì)應(yīng)的注釋部分:
“當(dāng)數(shù)據(jù)發(fā)生變化時(shí),將此標(biāo)志設(shè)置為
True
。僅跟蹤會(huì)話字典本身;如果會(huì)話包含可變數(shù)據(jù)(例如嵌套的字典),則在修改該數(shù)據(jù)時(shí)必須手動(dòng)將此標(biāo)志設(shè)置為True
。僅當(dāng)此標(biāo)志為True
時(shí),會(huì)話cookie才會(huì)寫入響應(yīng)中?!?/p>
進(jìn)第一個(gè)父類:
調(diào)用on_update函數(shù)了就會(huì)給modified設(shè)為True。
所以:
session['user_info'] = 'abc' # session.__setitem__
session['user_info'][('name')]
第一行會(huì)修改,但是第二行是調(diào)用的__getitem__
,而源碼(上圖)沒有相關(guān)處理,所以不會(huì)保存。
解決方法:
再來看下源碼(上面沒有看完的部分):
進(jìn)去看,因?yàn)樵O(shè)置了modified為True,所以這個(gè)should_set_cookie
就為True,所以這個(gè)if就不成立,就繼續(xù)往下執(zhí)行。
不過這部分源碼給了我們另一個(gè)方法,如果設(shè)置SESSION_REFRESH_EACH_REQUEST
這個(gè)參數(shù)為True,每次請(qǐng)求session也都會(huì)修改(用這個(gè)方法解決):
而且推薦使用這個(gè)方法,推薦用這個(gè)的原因:
想象一個(gè)使用場景,如果用戶登錄一個(gè)網(wǎng)站,cookie設(shè)置的二十分鐘失效,如果這個(gè)過程中用戶一直沒有做cookie相關(guān)的操作,那么20分鐘后登錄就失效了,但是如果這二十分鐘用戶一直在訪問這個(gè)網(wǎng)站,是不應(yīng)該讓用戶失效的。
如果設(shè)置了上述這個(gè)參數(shù)為True,就不會(huì)出現(xiàn)這種問題,
SESSION_REFRESH_EACH_REQUEST
的行為是在用戶請(qǐng)求時(shí)將會(huì)話標(biāo)記為“新的”(fresh),以確保它在每個(gè)請(qǐng)求之后都會(huì)被刷新。這意味著,無論用戶是否刷新瀏覽器或進(jìn)行其他操作,都會(huì)重置會(huì)話的過期時(shí)間。這是為了確保用戶在與應(yīng)用交互期間會(huì)話不會(huì)過期(過期時(shí)間會(huì)從用戶刷新的時(shí)間重新往后計(jì)算)
Flask中使用的話,要在登錄成功后設(shè)置一下permanent也為True(但是如果用flask-session就不用了,因?yàn)檫@個(gè)默認(rèn)是為True):文章來源:http://www.zghlxwxcb.cn/news/detail-842024.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-842024.html
到了這里,關(guān)于(二十五)Flask之MTV&MVC架構(gòu)模式Demo【重點(diǎn):原生session使用及易錯(cuò)點(diǎn)!】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!