Flask藍本理解 - 形象生動

作者:杜志鵬

鏈接:https://www.zhihu.com/question/31748237/answer/55313054

來源:知乎

著作權歸作者所有,轉載請聯系作者獲得授權。

分白話版和專業版 :)

白話版

恩,理解「藍本」對于沒有接觸其他Web編程實現的Python+Flask新手而言,是一個不好邁過的坎兒。

我得用「比喻」的方式穿插講述一下「藍本」,方便你更好理解,問這個問題估計是新手,所以我啰嗦點好了。

首先,提一下概念,「藍本」的對應官方詞匯是「Blueprint」,中譯還有「藍圖」這種叫法,是一種東西。

你去餐館吃飯,點一些菜,你一定吃過「麻辣香鍋」這種東西。你可以點一些雜七雜八的菜,選好口味,之后一個碗兒端上來,你吃的很滋味,并且也會覺得這種「一鍋端」的方式很好,畢竟不會一道吃完等下一道啊,一起上來熱乎乎的多好。并且吃的很少的時候,一點點的菜單獨用一個碗兒裝也是有點「裝逼」的事情。

假如你一個人一己之力要寫一個BBS(論壇系統)的話,上面的這個例子,其真實寫照是初期功能很弱時,可能頁面不多,實現的功能也很少。可能首頁就是一個帖子列表,允許用戶發布帖子,并且不涉及登錄退出、會員等級、權限管理等,你想著,那是后面再說的事情。于是,你將網站主干代碼寫在一個run.py文件里,讓網站成功的跑了起來,你覺得這樣實現很方便,快捷。

如果我讓你這個時候把run.py理一下,能獨立出來的獨立成其他的文件,之后在run.py里導入,你要罵我「裝逼」了,沒事找事。是的,「藍本」并不適合用來構建想當簡單的網站系統。

然而,你胃口變大了,你也有了好朋友,你們要一起去吃飯。于是你遇到一些問題:

你的朋友不喜歡吃某些東西,但你喜歡吃。你朋友喜歡吃的一些東西,你不喜歡吃。

人多了,點的東西多了,你們想如果吃不完可以打包明天吃,但是你們打包還是要挑一些菜打包的,畢竟有些菜隔夜就味道不好,容易壞掉。

你和你的朋友都想先吃一種東西,然后再吃一種東西。比如先吃點葷的,然后吃點素的解解葷。

以上,如果你們還去吃「麻辣香鍋」,就都不開心了,你想想看。

類似的,當你的BBS系統越來越復雜,有了登錄退出、會員等級、權限管理等等功能后,問題迎面而來:

run.py文件肯定越來越大,代碼行數越來越多。你網站所有的路由寫在一個文件里,功能也在一個文件里,很容易出現錯誤,并且難以定位。當然,你如果沒實戰經驗,確實不能切身體會這點。那么我說另一個顯而易見的問題:import(導入)和config(配置)一般寫在頭部,你的新路由按順序怎么也得寫在幾百行開外的地方,于是你編程時一下看代碼文件最上面,一下拖到底部繼續寫,這就夠「操蛋」的了。

大型網站一定是多人編程,如果此刻安排你做登錄退出功能,你的朋友做權限管理功能,那么老板當然不容忍你干完你朋友才開工,一起開干啊!可是此時只有run.py一個文件,沒錯,你和你的基友可以各自拷貝一份run.py各自開始寫,結果你的代碼從第100行開始寫,你的朋友也從100行開始寫,然后你們還各自在頭部import了一些新東西。等寫好了,怎么辦?線上就一個run.py,這下「糟糕」了,苦苦「合并」代碼嗎?這更「操蛋」了。如果10個人寫網站呢?——「蛋蛋艸碎了」

所以,你此刻第一反應當然是「麻辣香鍋」吃不成了,這「一碗菜是一碗菜」的方式是最佳的解決方案,愛吃什么吃什么,愛打包哪碗直接裝起來,不用拿著筷子挑。

當你利用Python+Flask構建一個網站時,人為的提煉一些代碼獨立成文件是「不妥」的方式,你需要Flask本身給予一些支持,于是「藍本」出現了。

「藍本」允許你將不同路由分開,提供一些「規范(標準)」,并且附帶了很多好處。你可以要求商家不同的菜上來裝不同的盤子,就像你也可以要求「藍本」針對不同路由應用不同靜態資源,導致不同的URL出現不一樣的網站界面(否則前端CSS就混雜了)。

「藍本」使得你和基友一起工作時不會再有上面的麻煩事,你改你的A文件,他改他的B文件,回頭各自提交各自的,多好。

「藍本」讓你做另一個程序時,如果那個程序也有登錄退出,理想情況下你甚至可以直接將BBS負責登錄退出的部分直接挪過去用,這遠比直接從一個run.py里復制出代碼現實的多,要知道即使一個登錄退出的功能,你在一個run.py里實現,代碼會散落在各處的。

「藍本」還有其他好處,其實本質上來說就是讓程序更加松耦合,更加靈活,增加復用性,提高查錯效率,降低出錯概率。

專業版

正常情況下,入門Flask框架都是從寫一個單文件,然后看到頁面顯示 Hello,World! 開始的。這個單文件一般命名hello.py或run.py。

你會在單文件中寫一些路由,比如首頁的、列表頁的、詳情頁的,就像我博客這么簡單的頁面結構,完全可以一個文件搞定。

# -*- coding: utf-8 -*-# run.pyfromflaskimportFlask,render_template,requestfromflask_flatpagesimportFlatPagesFLATPAGES_AUTO_RELOAD=TrueFLATPAGES_ROOT='pages'FLATPAGES_EXTENSION='.md'app=Flask(__name__)app.config.from_object(__name__)flatpages=FlatPages(app)@app.route('/')defindex():returnrender_template('index.html')@app.route('/list//')defpage_list(tag):articles=(pforpinflatpagesiftaginp['tags'])pages=sorted(articles,reverse=True,key=lambdap:p.meta['date'])returnrender_template('list.html',tag=tag,pages=pages)@app.route('/page//')defpage(uri):p=flatpages.get_or_404(uri)returnrender_template('page.html',p=p)if__name__=='__main__':app.run()

上面是一個可以運行的微型博客的全部后端程序,幾乎就是你現在正常訪問的博客的全部,你看,非常簡短!

如果你用過類似WordPress或者新浪博客等博客工具,顯然有一個問題:哪兒可以添加新的文章和管理文章分類?的確,這段代碼離一個傳統的博客程序該有的全貌相差甚遠,因為還欠缺一個管理后臺。

以WordPress為例子,在一般情況下,如果訪問如http://xxx.com,可以看到博客的前臺,也就是各種博客文章。而訪問如http://xxx.com/wp-admin則可以進入到后臺,用來管理文章和發布新文章。在路由的寫法上,對于上面這個文件你可能要這樣擴充一下功能(為了節省篇幅方便演示,下面代碼詳細部分省略,以 pass 代替詳細部分)。

# -*- coding: utf-8 -*-# run.pyfrom flask import Flask, render_template, requestfrom flask_flatpages import FlatPagesFLATPAGES_AUTO_RELOAD = TrueFLATPAGES_ROOT = 'pages'FLATPAGES_EXTENSION = '.md'app = Flask(__name__)app.config.from_object(__name__)flatpages = FlatPages(app)@app.route('/')def index():pass? # 為了方便演示這里省略詳細代碼@app.route('/list//')def page_list(tag):pass@app.route('/page//')

def page(uri):

pass

# 新增的后臺部分代碼

from adminPages import admin

app.register_blueprint(admin, url_prefix='/admin')

if __name__ == '__main__':

app.run()

上述代碼新增加了管理后臺部分,具體是增加了一個后臺登錄界面、文章列表以及新增和編輯文章的功能共四個部分。

繼續上述思路,可以想到新的幾個問題:

1)一般情況下,前臺和后臺用兩套模板。或者通俗的講,前臺費力弄得好看點,后臺反正自己用,能用就成,丑點無所謂。那么怎么讓前臺和后臺用兩套模板?

2)后臺部分邏輯比前臺復雜,還需要導入新的包,如果和前臺寫在一個文件里,后面修改會不會容易出錯,例如本來改后臺部分結果牽連前臺出問題?

3)既然Python力求簡潔,那代碼能否再簡潔些?比如新增的路由參數 /admin 重復寫了4遍,能不能對后臺定義一個前綴,后臺部分的自動加這個/admin ?

4)如果這個博客程序需要多人來維護,多人編輯同一個文件去提交時沖突如何解決?

亦或者你還有其他的一些疑問,如果是關乎怎么把程序做大的同時,還能保證簡潔、良好、易于維護的代碼組織結構,一個容易想到的方向就是程序的「模塊化」。

在你學習Python的過程中,早已見識到了Python模塊化,比如Python的包概念,也即你總是能看到的 import …… 引入的那些東西和本身的這個引入方法。那么,對于Flask而言,你也許會舉一反三的把博客的后臺程序部分抽離出來,單獨編寫一個文件,然后再 import ……? ,這樣不就模塊化了?!

但是等等,程序跑不起來了?還有,前面剛提到過的四個問題,似乎這樣做之后只是勉強解決了第四個問題,前三個呢?

所以,可想而知,我們 的確需要一個模塊化的方法,這個思路的方向本身不錯,要點在于我們需要的是一個Flask認可的、兼容的、支持的模塊化方法。Flask的作者作為一個老江湖早就考慮到這點,并提供了一個名為Blueprint的方法來讓你實現模塊化組織程序結構。

Blueprint中文的翻譯現在有兩種常見的:藍圖以及藍本。這里我們稱藍圖好了。

對于上述程序,我們應用藍圖方法修改之后,大致是下面這樣了。

首先,我們新增一個文件adminPages.py,如下:

# -*- coding: utf-8 -*-# adminPages.pyfromflaskimportBlueprintadmin=Blueprint('admin',__name__)@admin.route('/login/')defadmin_login():pass@admin.route('/page/')defadmin_pages():pass@admin.route('/page/new/')defnew_page():pass@admin.route('/page/edit/')defedit_page():pass

同時,改寫run.py 如下:

# -*- coding: utf-8 -*-# run.pyfromflaskimportFlask,render_template,requestfromflask_flatpagesimportFlatPagesFLATPAGES_AUTO_RELOAD=TrueFLATPAGES_ROOT='pages'FLATPAGES_EXTENSION='.md'app=Flask(__name__)app.config.from_object(__name__)flatpages=FlatPages(app)@app.route('/')defindex():pass# 為了方便演示這里省略詳細代碼@app.route('/list//')defpage_list(tag):pass@app.route('/page//')defpage(uri):pass# 新增的后臺部分代碼fromadminPagesimportadminapp.register_blueprint(admin,url_prefix='/admin')if__name__=='__main__':app.run()

好,這就完成了一個應用藍圖的簡單例子。讓我們再來回顧上述代碼,看看都做了些什么。

首先,我們新增了一個adminPages.py的文件,并在文件中導入了Flask的藍圖方法Blueprint。

緊接著,我們用admin實例化了一個藍圖應用,就是這句:

admin=Blueprint('admin',__name__)

Blueprint要求至少傳入兩個參數,分別是藍圖的名字和藍圖所在的包或模塊。

我們將后臺部分獨立出來作為藍圖模塊,并取名為 admin ,所以我們傳入第一個參數'admin'。

緊接著是所在的包或模塊,如果你有印象,大概還記得Python有一個特殊屬性_ name _ ,當用在一個文件里時,代表的是模塊(或包)的名字,所以第二個參數傳入 _ name _ 。

因為使用了藍圖,原來的路由 @app.route() 改寫成了 @admin.route(),改寫的原因你需要看一下官方文檔了解更為深入的細節,這里暫且不表。

對于run.py,我們剝離出了 admin 部分的程序代碼,但在文件末尾,又導入了藍圖模塊,然后按照Flask藍圖的用法去注冊了藍圖,就是這兩行代碼:

fromadminPagesimportadminapp.register_blueprint(admin,url_prefix='/admin')

其中,app.register_blueprint()的第一個參數無需過多解釋,第二個參數 url_prefix= 即在定義前綴。還記得前面的四個問題嗎?這里針對的就是第三個問題。再回過頭去看看,你會發現adminPages.py里,原來路由里的 /admin 都去掉了。

就是這些,我們簡單的應用了一把Flask的藍圖功能,一定程度上算是解決了前面四個問題中的三個,還有一個兩套模板的問題藍圖也支持,并且十分簡單,留給你去看看官方文檔了解吧。

提示:template_folder=

以上,我所說的針對「小白」新手,如果你有一定的實踐經驗,官方的文檔寫得更準確些:使用藍圖的模塊化應用

希望我的回答幫你繞好彎子。: P

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • 22年12月更新:個人網站關停,如果仍舊對舊教程有興趣參考 Github 的markdown內容[https://...
    tangyefei閱讀 35,207評論 22 257
  • 解釋1: 允許將應用組織為模塊,每個模塊有自洽的 MVC,開發者做些工作可以使模塊間依賴盡可能少,必要時可以按 b...
    大詩兄_zl閱讀 2,229評論 1 1
  • flask是python的一個web應用框架,django很多人聽過,flask比較少見,連創始人一開始寫出來只是...
    思而憂閱讀 2,953評論 0 5
  • 第七章 大型程序架構 雖然在一個腳本里完成一個web應用很便利,但是這也意味著它很難擴展。當程序不斷增長,越來越復...
    易木成華閱讀 926評論 0 1
  • 什么是藍圖? 一個藍圖定義了視圖,模板,靜態文件以及可以用于應用程序的其它元素的集合。例如,讓我們假設下我們有一個...
    邪惡的Sheldon閱讀 1,257評論 0 1