選擇一個 Python Web 框架:Django vs Flask vs Pyramid

Pyramid, Django, 和 Flask都是優秀的框架,爲項目選擇其中的哪個都是傷腦筋的事。咱們將會用三種框架實現相同功能的應用來更容易的對比三者。也能夠直接跳到框架實戰(Frameworks in Action)章節查看代碼(code)。css

1 簡介

世界上可選的基於Python的web框架有不少。Django, Flask, Pyramid, Tornado, Bottle, Diesel, Pecan, Falcon等等,都在爭取開發者支持。做爲一開發者從一堆選擇中篩選出一個來完成項目將會成爲下一個大工程。咱們今天專一於Flask, Pyramid, 和 Django。它們涵蓋了從小微項目到企業級的web服務。html

爲了更容易在三者中做出選擇(至少更瞭解它們),咱們將用每個框架構建一樣的應用並比較它們的代碼,對於每個方法咱們會高亮顯示它的優勢和缺點。若是你只想要代碼,直接跳到框架實戰章節(Frameworks in Action),或者查看其在Github上的代碼。前端

Flask是一個面向簡單需求小型應用的「微框架(microframework)」。Pyramid和Django都是面向大型應用的,可是有不一樣的拓展性和靈活性。Pyramid的目的是更靈活,可以讓開發者爲項目選擇合適的工具。這意味着開發者可以選擇數據庫、URL結構、模板類型等等。Django目的是囊括web應用的全部內容,因此開發者只須要打開箱子開始工做,將Django的模塊拉進箱子中。python

Django包括一個開箱即用的 ORM ,而Pyramid和 Flask讓開發者本身選擇如何或者是否存儲他們的數據。到目前爲止對於非Django的web應用來講最流行的ORM是SQLAlchemy,同時還有多種其餘選擇,從 DynamoDBMongoDB 到簡單本地存儲的LevelDB 或樸實的SQLite。Pyramid被設計爲可以使用任何數據持久層,甚至是尚未開發出來的。git

二、關於框架

Django的」batteries included」 特性讓開發者不須要提早爲他們的應用程序基礎設施作決定,由於他們知道Python已經深刻到了web應用當中。Django已經內建了模板、表單、路由、認證、基本數據庫管理等等。比較起來,Pyramid包括路由和認證,可是模板和數據庫管理須要額外的庫。程序員

前面爲 Flask和Pyramid apps選擇組件的額外工做給那些使用案例不適用標準ORM的開發者提供了更多的靈活性,一樣也給使用不一樣工做流和模版化系統的開發者們帶來了靈活性。github

Flask,做爲三個框架裏面最稚氣的一個,開始於2010年年中。Pyramid框架是從Pylons項目開始的,在2010年末得到 Pyramid這個名字,雖然在2005年就已經發布了第一個版本。Django 2006年發佈了第一個版本,就在Pylons項目(最後叫Pyramid)開始以後。Pyramid和Django都是很是成熟的框架,積累了衆多插件和擴展以知足難以置信的巨大需求。web

雖然Flask歷史相對更短,但它可以學習以前出現的框架而且把注意力放在了微小項目上。它大多數狀況被使用在一些只有一兩個功能的小型項目上。例如 httpbin,一個簡單的(但很強大的)調試和測試HTTP庫的項目。sql

3. 社區

最具活力的社區當屬Django,其有80,000個StackOverflow問題和一系列來自開發者和優秀用戶的良好的博客。Flask和Pyramid社區並無那麼大,但它們的社區在郵件列表和IRC上至關活躍。StackOverflow上僅有5,000個相關的標籤,Flask比Django小了15倍。在Github上,它們的star近乎至關,Django有11,300個,Flask有10,900個。mongodb

三個框架都使用的是BSD衍生的協議。FlaskDjango的協議是BSD 3條款,Pyramid的Repoze Public License RPL是BSD協議 4條款的衍生。

4. Bootstrapping

Django和Pyramid都內建bootstrapping工具。Flask沒有包含相似的工具,由於Flask的目標用戶不是那種試圖構建大型MVC應用的人。

4.1 Flask

Flask的hello world應用很是的簡單,僅僅單個Python文件的7行代碼就夠了。

這是Flask沒有bootstrapping工具的緣由:沒有它們的需求。從Flask主頁上的Hello World特性看,沒有構建Python web應用經驗的開發者能夠當即開始hacking。

對於各部分須要更多分離的項目,Flask有blueprints。例如,你能夠將全部用戶相關的函數放在users.py中,將銷售相關的函數放在ecommerce.py中,而後在site.py中添加引用它們來結構化你的Flask應用。咱們不會深刻這個功能,由於它超出了咱們展現demo應用的需求。

4.2 Pyramid

Pyramid 的 bootstrapping工具叫 pcreate,是Pyramid的組成部分. 以前的 Paste 工具套裝提供了 bootstrapping ,可是從那以後被 Pyramid專用工具鏈替代了。

Pyramid 比 Flask 適用於更大更復雜的應用程序. 由於這一點,它的 bootstrapping工具建立更大的項目骨架. Pyramid 一樣加入了基本的配置文件,一個例子模版和用於將程序打包上傳到 Python Package Index的全部文件。

做爲最後描述的框架,Pyramid的bootstrapper很是靈活. 不侷限於一個默認的程序;pcreate 可使用任意數量的項目模版. 包括咱們上面用到的pcreate裏面的」starter」的模版, 還有 SQLAlchemy- ,ZODB-支持scaffold項目. 在 PyPi能夠發現已經爲Google App Engine, jQuery Mobile, Jinja2 templating, modern frontend frameworks作好的scaffolds, 還有更多~

4.3 Django

Django 也有本身的 bootstrap 工具, 內置在 django-admin 中.

Django 跟 Pyramid 區別在於: Django 由多個應用程序組成一個項目, 而 Pyramid 以及 Flask 項目是包含 View 和 Model 單一應用程序 . 理論上, Flask 和 Pyramid 的項目容許存在多個 project/app, 不過在默認配置中只能有一個.

Django 默認只在項目中建立 空白的 model 和模板文件, 供新手參考的示範代碼很少. 此外, 開發者在發佈應用程序的時候, 還要本身配置, 這也是個麻煩.

bootstrap 工具的缺點是沒有指導開發者如何打包應用. 對於那些沒有經驗的新手來講, 第一次部署應用將是個很頭疼的問題. 像 django-oscar 這樣的大社區, 項目都是打包好了, 放在 PyPi 上供你們安裝. 可是 Github 上面的小項目缺乏統一的打包方式.

5 模板

一個Python應用可以響應HTTP請求將是一個偉大的開端,可是有可能你的大多數用戶是沒有興趣使用curl與你的web應用交互的。幸運的是,這三個競爭者提供了使用自定義信息填充HTML的方法,以便讓大夥們可以享受時髦的Bootstrap 前端。

模板讓你可以直接向頁面注入動態信息,而不是採用AJAX。你只須要一次請求就能夠獲取整個頁面以及全部的動態數據,這對用戶體驗來講是很好的。這對於手機網站來講尤爲重要,由於一次請求花費的時間會更長。

全部的模板選項依賴於「上下文環境(context)」,其爲模板轉換爲HTML提供了動態信息。模板的最簡單的例子是填充已登陸用戶的名字以正確的迎接他們。也能夠用AJAX獲取這種動態信息,可是用一整個調用來填寫用戶的名字有點過頭了,而同時模板又是這麼的簡單。

5.1 Django

咱們使用的例子正如寫的那麼簡單,假設咱們有一個包含了用戶名的funllname屬性的user對象。在Python中咱們這樣向模板中傳遞當前用戶:

擁有這個模板的上下文很簡單,傳入一個Python對象的字典和模板使用的數據結構。如今咱們須要在頁面上渲染他們的名字,以防頁面忘了他們是誰。

首先,你會注意到這個 {% if user %} 概念。在Django模板中, {% 用來控制循環和條件的聲明。這裏的if user聲明是爲了防止那些不是用戶的狀況。匿名用戶不該該在頁面頭部看到「你已經登陸」的字樣。

在if塊內,你能夠看到,包含名字很是的簡單,只要用{{}}包含着咱們要插入的屬性就能夠了。{{是用來向模板插入真實值的,如{{ user.fullname }}。

模板的另外一個經常使用狀況是展現一組物品,如一個電子商務網站的存貨清單頁面。

在模板中,咱們使用一樣的{%來循環清單中的全部條目,並填入它們各自的頁面地址。

爲了作大部分常見的模板任務,Django能夠僅僅使用不多的結構來完成目標,所以很容易上手。

5.2 Flask

Flask默認使用受Django啓發的Jinja2模板語言,但也能夠配置來使用另外一門語言。不該該抱怨一個倉促的程序員分不清Django和Jinja模板。事實是,上面的Django例子在Jinja2也有效。爲了避免去重複相同的例子,咱們來看下Jinja2比Django模板更具表現力的地方。

Jinja和Django模板都提夠了過濾的特性,即傳入的列表會在展現前經過一個函數。一個擁有博文類別屬性的博客,能夠利用過濾特性,在一個用逗號分割的列表中展現博文的類別。

在Jinja模板語言中,能夠向過濾器傳入任意數量的參數,由於Jinja把它當作是 使用括號包含參數的Python函數的一個調用。Django使用冒號來分割過濾器的名字和過濾參數,這限制了參數的數目只能爲一。

Jinjia和Django的for循環有點相似。咱們來看看他們的不一樣。在Jinjia2中,for-else-endfor結構能遍歷一個列表,同時也處理了沒有項的狀況。

Django版的這個功能是同樣的,可是是用for-empty-endfor而不是for-else-endfor。

除了語法上的不一樣,Jinja2經過執行環境和高級特性提供了更多的控制。例如,它能夠關閉危險的特性以安全的執行不受信任的模板,或者提早編譯模板以確保它們的合法性。

5.3 Pyramid

與Flask相似,Pyramid支持多種模板語言(包括Jinja2和Mako),可是默認只附帶一個。Pyramid使用Chameleon,一個 ZPT (Zope Page Template) 模板語言的實現。咱們來回頭看看第一個例子,添加用戶的名字到網站的頂欄。Python代碼除了明確調用了render_template函數外其餘看起來都差很少。

可是咱們的模板看起來有些不一樣。ZPT是一個基於XML得模板標準,因此咱們使用了類XSLT語句來操做數據。

Chameleon對於模板操做有三種不一樣的命名空間。TAL(模板屬性語言)提供了基本的條件語句,字符串的格式化,以及填充標籤內容。上面的例子只用了TAL來完成相關工做。對於更多高級任務,就須要TALES和METAL。TALES( 模板屬性表達式語法的語言)提供了像高級字符串格式化,Python表達式評估,以及導入表達式和模板的表達式。

METAL(宏擴展模板屬性語言)是Chameleon模板最強大的(和複雜的)一部分。宏是可擴展的,並能被定義爲帶有槽且當宏被調用時能夠被填充。

6. 利用框架行動起來

對於各個框架,咱們將經過製做一個叫作wut4lunch的應用來了解,這個應用是告訴整個互聯網你午餐吃了什麼的社交網絡。很自由的一個起始想法,徹底能夠隨意改變。應用將有一個簡單的接口,容許用戶提交他們午餐的內容,並看到其餘用戶吃的什麼的列表。主頁完成後將看起來像這樣。

cpp_py_medium

6.1 使用Flask的Demo應用

最短的實現用了34行Python代碼和一個22行的Jinja模板。首先,咱們有些管理類的任務要作,好比初始化咱們的應用並拉近咱們的ORM。

如今咱們看下咱們的模型,這將和另兩個樣例基本同樣。

哇,至關簡單。最難的部分是找到合適的 SQLAlchemy數據類型,選擇數據庫中String域的長度。使用咱們的模型也超級簡單,這在於咱們將要看到 SQLAlchemy查詢語法
構建咱們的提交表單也很簡單。在引入Flask-WTForms和正確的域類型後,你能夠看到表單看起來有點像咱們的模型。主要的區別在於新的提交按鈕和食物與提交者姓名域的提示。

應用中的SECRET_KEY域是被WTForms用來建立CSRF符號的。它也被itsdangerous(Flask內包含)用來設置cookies和其餘數據。

讓表單在瀏覽器中顯示意味着模板要有它。咱們像下面那樣傳遞進去。

好了,發生了什麼?咱們獲得已經用Lunch.query.all()提交的午飯列表,並實例化一個表單,讓用戶提交他們本身的美食之旅。爲了簡化,變量使用相同的名字出入模板,但這不是必須的。

這就是模板的真實狀況,咱們在已經吃過的午飯中循環,並在<ul>中展現他們。這幾乎與咱們前面看到的循環例子同樣。

模板的<form>部分僅僅渲染咱們在root()視圖中傳入模板的WTForm對象的表單標籤和輸入。當表單提交時,它將向/new提交一個POST請求,這個請求會被下面的函數處理。

在驗證了表單數據後,咱們把內容放入咱們Model對象中,並提交到數據庫。一旦咱們在數據庫中存了午飯,它將在人們吃過的午飯列表中出現。

最後,咱們只需作(很是)少許的工做來讓應用運行起來。使用SQLAlchemy,咱們能夠建立存儲午飯的表,而後開始運行咱們寫的路徑管理就好了。

6.2 測試Django版APP

Django版wut4lunch 和Flask版有點像,可是在Django項目中被分到了好幾個文件中。首先,咱們看看最類似的部分:數據庫模型。它和SQLAlchemy版本的惟一不一樣之處是聲明保存文本的數據庫字段有輕微的語法區別。

在表單系統上。不像Flask,咱們能夠用Django內建的表單系統。它看起來很是像咱們在Flask中使用的WTFroms模塊,只是語法有點不一樣。

如今咱們只須要構造一個LunchForm實例傳遞到咱們的模板。

render函數是Django shortcut,以接受請求、模板路徑和一個上下文的dict。與Flask的render_template相似,它也接受接入請求。

保存表單應答到數據庫是不同的,Django調用模型的 .save()方法以及處理會話管理而不是用全局數據庫會話。乾淨利落!

Django提供了一些優雅的特性,讓咱們管理用戶提交的午飯,所以咱們能夠刪除那些不合適的午飯信息。Flask和Pyramid沒有自動提供這些功能,而在建立一個Django應用時不須要寫另外一個管理頁面固然也是其一個特性。開發者的時間可難免費啊!咱們所要作的就是告訴Django-admin咱們的模型,是在wut5lunch/admin.py中添加兩行。

Bam。如今咱們能夠添加刪除一些條目,而無需額外的工做。

最後,讓咱們看下主頁模板的不一樣之處。

Django擁有方便的快捷方式,在你的頁面中引用其餘的視圖。url標籤可使你重建應用中的URLs,而不需破壞視圖。這個是由於url標籤會主動查詢視圖中的URL。

表單被不一樣的語法渲染,咱們須要人工在表單主體中添加CSRF token,但這些區別更多的是裝飾

6.3測試Pyramid版App

最後,咱們看看用Pyramid實現的一樣的程序。與Django和Flask的最大不一樣是模板。只須要對Jinja2作很小的改動就足以解決咱們在Django中的問題。此次不是這樣的,Pyramid的Chameleon模板的語法更容易讓人聯想到XSLT而不是別的。

與Django模板相似,缺乏for-else-endfor結構使得邏輯稍微的更清晰了。這種狀況下,咱們以if-for 和 if-not-for 語句塊結尾以提供一樣的功能。使用{{或{%來控制結構和條件的Django以及AngularJS類型的模板讓使用XHTML標籤的模板顯得很外行。

Chameleon模板類型的一大好處是你所選擇的編輯器能夠正確的使語法高亮,由於模板是有些得XHTML。對於Django和Flask模板來講,你的編輯器須要可以正確的支持這些模板語言高亮顯示。

Pyramid中表單得轉換稍微更細緻些,由於pytamid_simpleform不像Django表單的form.as_ul函數那樣能夠自動轉換全部的表單字段。

如今咱們看看什麼返回給應用。首先,定義咱們須要得表單並呈現咱們的主頁。

獲取午飯的查詢語法和Flask的很類似,這是由於這兩個demo應用使用了流行的SQLAlchemy ORM來提供持久存儲。在Pyramid中,容許你直接返回模板上下文的字典,而不是要調用特殊的render函數。@view_config裝飾器自動將返回的上下文傳入要渲染的模板。避免調用render方法使得Pyramid寫的函數更加容易測試,由於它們返回的數據沒有被模板渲染對象掩蓋。

從Pyramid的請求對象中更加容易獲得表單數據,由於在咱們獲取時會自動將表單POST數據解析成dict。爲了阻止同一時間多併發的請求數據庫,ZopeTransactions模塊提供了上下文管理器,對寫入邏輯事物的數據庫進行分組,並阻止應用的線程在各個改變時互相影響,這在你的視圖共享一個全局session並接收到大量通訊的狀況下將會是個問題。

7. 總結

Pyramid是三個中最靈活的。它能夠用於小的應用,正如咱們所見,但它也支撐着有名的網站如Dropbox。開源社區如Fedora選擇它開發應用,如他們社區中的徽章系統,從項目工具中接受事件的信息,並向用戶獎勵成就類型的徽章。對於Pyramid的一個最多見的抱怨是,它提供了這麼多的選項,以致於用它開始一個新項目很嚇人。

目前最流行的框架是Django,使用它的網站列表也使人印象深入。Bitbucket,Pinterest,Instagram,以及Onion徹底或部分使用Django。對於有常見需求的網站,Django是很是理智的選擇,也所以它成爲中大型網站應用的流行選擇。

Flask對於那些開發小項目、須要快速製做一個簡單的Python支撐的網站的開發者頗有用。它提供小型的統一工具,或者在已有的API上構建的簡單網絡接口。能夠快速開發須要簡單web接口並不怎麼配置的後端項目使用Flask將會在前端獲益,如jitviewer提供了一個web接口來檢測PyPy just-in-time的編譯日誌。

這三個框架都能解決咱們簡單的需求,咱們已經看到了它們的不一樣。這些區別不只僅是裝飾性的,它們將會改變你設計產品的方法,以及添加新特性和修復的速度。由於咱們的例子很小,咱們看到Flask的閃光點,以及Django在小規模應用上的笨重。Pyramid的靈活並未體現出來,由於咱們的要求是同樣的,但在真實場景中,新的需求會經常出現。

7.1 致謝

標題圖像的logo來自與Flask、Django和Pyramid項目網站。

這篇文章很是感謝它的評閱者,Remy DeCausemaker,Ross Delinger和Liam Middlebrook,忍受了許多初期的草稿。

這篇文章的當前樣式來自於Adam Chainz、bendwarn、Serger Maertens、Tom Leo和wichert的評論和修正(名字按字母表順序)。

相關文章
相關標籤/搜索