新聞中心
Pyramid, Django, 和 Flask都是優(yōu)秀的框架,為項目選擇其中的哪一個都是傷腦筋的事。我們將會用三種框架實現(xiàn)相同功能的應(yīng)用來更容易的對比三者。也可以直接跳到框架實戰(zhàn)(Frameworks in Action)章節(jié)查看代碼(code)。

讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:主機域名、虛擬主機、營銷軟件、網(wǎng)站建設(shè)、三門峽網(wǎng)站維護、網(wǎng)站推廣。
1. 簡介
世界上可選的基于Python的web框架有很多。Django, Flask, Pyramid, Tornado, Bottle, Diesel, Pecan, Falcon等等,都在爭取開發(fā)者支持。作為一開發(fā)者從一堆選擇中篩選出一個來完成項目將會成為下一個大工程。我們今天專注于Flask, Pyramid, 和 Django。它們涵蓋了從小微項目到企業(yè)級的web服務(wù)。
為了更容易在三者中作出選擇(至少更了解它們),我們將用每一個框架構(gòu)建同樣的應(yīng)用并比較它們的代碼,對于每一個方法我們會高亮顯示它的優(yōu)點和缺點。如果你只想要代碼,直接跳到框架實戰(zhàn)章節(jié)(Frameworks in Action),或者查看其在Github上的代碼。
Flask是一個面向簡單需求小型應(yīng)用的“微框架(microframework)”。Pyramid和Django都是面向大型應(yīng)用的,但是有不同的拓展性和靈活性。Pyramid的目的是更靈活,能夠讓開發(fā)者為項目選擇合適的工具。這意味著開發(fā)者能夠選擇數(shù)據(jù)庫、URL結(jié)構(gòu)、模板類型等等。Django目的是囊括web應(yīng)用的所有內(nèi)容,所以開發(fā)者只需要打開箱子開始工作,將Django的模塊拉進箱子中。
Django包括一個開箱即用的 ORM ,而Pyramid和 Flask讓開發(fā)者自己選擇如何或者是否存儲他們的數(shù)據(jù)。到目前為止對于非Django的web應(yīng)用來說***的ORM是SQLAlchemy,同時還有多種其他選擇,從 DynamoDB和MongoDB 到簡單本地存儲的LevelDB 或樸實的SQLite。Pyramid被設(shè)計為可使用任何數(shù)據(jù)持久層,甚至是還沒有開發(fā)出來的。
2.關(guān)于框架
Django的”batteries included” 特性讓開發(fā)者不需要提前為他們的應(yīng)用程序基礎(chǔ)設(shè)施做決定,因為他們知道Python已經(jīng)深入到了web應(yīng)用當中。Django已經(jīng)內(nèi)建了模板、表單、路由、認證、基本數(shù)據(jù)庫管理等等。比較起來,Pyramid包括路由和認證,但是模板和數(shù)據(jù)庫管理需要額外的庫。
前面為 Flask和Pyramid apps選擇組件的額外工作給那些使用案例不適用標準ORM的開發(fā)者提供了更多的靈活性,同樣也給使用不同工作流和模版化系統(tǒng)的開發(fā)者們帶來了靈活性。
Flask,作為三個框架里面最稚氣的一個,開始于2010年年中。Pyramid框架是從Pylons項目開始的,在2010年底獲得 Pyramid這個名字,雖然在2005年就已經(jīng)發(fā)布了***個版本。Django 2006年發(fā)布了***個版本,就在Pylons項目(***叫Pyramid)開始之后。Pyramid和Django都是非常成熟的框架,積累了眾多插件和擴展以滿足難以置信的巨大需求。
雖然Flask歷史相對更短,但它能夠?qū)W習之前出現(xiàn)的框架并且把注意力放在了微小項目上。它大多數(shù)情況被使用在一些只有一兩個功能的小型項目上。例如 httpbin,一個簡單的(但很強大的)調(diào)試和測試HTTP庫的項目。
3. 社區(qū)
***活力的社區(qū)當屬Django,其有80,000個StackOverflow問題和一系列來自開發(fā)者和優(yōu)秀用戶的良好的博客。Flask和Pyramid社區(qū)并沒有那么大,但它們的社區(qū)在郵件列表和IRC上相當活躍。StackOverflow上僅有5,000個相關(guān)的標簽,F(xiàn)lask比Django小了15倍。在Github上,它們的star近乎相當,Django有11,300個,F(xiàn)lask有10,900個。
三個框架都使用的是BSD衍生的協(xié)議。Flask和Django的協(xié)議是BSD 3條款,Pyramid的Repoze Public License RPL是BSD協(xié)議 4條款的衍生。
4. Bootstrapping
Django和Pyramid都內(nèi)建bootstrapping工具。Flask沒有包含類似的工具,因為Flask的目標用戶不是那種試圖構(gòu)建大型MVC應(yīng)用的人。
4.1 Flask
Flask的hello world應(yīng)用非常的簡單,僅僅單個Python文件的7行代碼就夠了。
- # from http://flask.pocoo.org/ tutorial
- from flask import Flask
- app = Flask(__name__)
- @app.route("/") # take note of this decorator syntax, it's a common pattern
- def hello():
- return "Hello World!"
- if __name__ == "__main__":
- app.run()
這是Flask沒有bootstrapping工具的原因:沒有它們的需求。從Flask主頁上的Hello World特性看,沒有構(gòu)建Python web應(yīng)用經(jīng)驗的開發(fā)者可以立即開始hacking。
對于各部分需要更多分離的項目,F(xiàn)lask有blueprints。例如,你可以將所有用戶相關(guān)的函數(shù)放在users.py中,將銷售相關(guān)的函數(shù)放在ecommerce.py中,然后在site.py中添加引用它們來結(jié)構(gòu)化你的Flask應(yīng)用。我們不會深入這個功能,因為它超出了我們展示demo應(yīng)用的需求。
4.2 Pyramid
Pyramid 的 bootstrapping工具叫 pcreate,是Pyramid的組成部分. 之前的 Paste 工具套裝提供了 bootstrapping ,但是從那之后被 Pyramid專用工具鏈替代了。
- $ pcreate -s starter hello_pyramid # Just make a Pyramid project
Pyramid 比 Flask 適用于更大更復(fù)雜的應(yīng)用程序. 因為這一點,它的 bootstrapping工具創(chuàng)建更大的項目骨架. Pyramid 同樣加入了基本的配置文件,一個例子模版和用于將程序打包上傳到 Python Package Index的所有文件。
- hello_pyramid
- ├── CHANGES.txt
- ├── development.ini
- ├── MANIFEST.in
- ├── production.ini
- ├── hello_pyramid
- │ ├── __init__.py
- │ ├── static
- │ │ ├── pyramid-16x16.png
- │ │ ├── pyramid.png
- │ │ ├── theme.css
- │ │ └── theme.min.css
- │ ├── templates
- │ │ └── mytemplate.pt
- │ ├── tests.py
- │ └── views.py
- ├── README.txt
- └── setup.py
作為***描述的框架,Pyramid的bootstrapper非常靈活. 不局限于一個默認的程序;pcreate 可以使用任意數(shù)量的項目模版. 包括我們上面用到的pcreate里面的”starter”的模版, 還有 SQLAlchemy- ,ZODB-支持scaffold項目. 在 PyPi可以發(fā)現(xiàn)已經(jīng)為Google App Engine, jQuery Mobile, Jinja2 templating, modern frontend frameworks做好的scaffolds, 還有更多~
4.3 Django
Django 也有自己的 bootstrap 工具, 內(nèi)置在 django-admin 中.
- django-admin startproject hello_django
- django-admin startapp howdy # make an application within our project
Django 跟 Pyramid 區(qū)別在于: Django 由多個應(yīng)用程序組成一個項目, 而 Pyramid 以及 Flask 項目是包含 View 和 Model 單一應(yīng)用程序 . 理論上, Flask 和 Pyramid 的項目允許存在多個 project/app, 不過在默認配置中只能有一個.
- hello_django
- ├── hello_django
- │ ├── __init__.py
- │ ├── settings.py
- │ ├── urls.py
- │ └── wsgi.py
- ├── howdy
- │ ├── admin.py
- │ ├── __init__.py
- │ ├── migrations
- │ │ └── __init__.py
- │ ├── models.py
- │ ├── tests.py
- │ └── views.py
- └── manage.py
Django 默認只在項目中創(chuàng)建 空白的 model 和模板文件, 供新手參考的示范代碼不多. 此外, 開發(fā)者在發(fā)布應(yīng)用程序的時候, 還要自己配置, 這也是個麻煩.
bootstrap 工具的缺點是沒有指導(dǎo)開發(fā)者如何打包應(yīng)用. 對于那些沒有經(jīng)驗的新手來說, ***次部署應(yīng)用將是個很頭疼的問題. 像 django-oscar 這樣的大社區(qū), 項目都是打包好了, 放在 PyPi 上供大家安裝. 但是 Github 上面的小項目缺少統(tǒng)一的打包方式.
5. 模板
一個Python應(yīng)用能夠響應(yīng)HTTP請求將是一個偉大的開端,但是有可能你的大多數(shù)用戶是沒有興趣使用curl與你的web應(yīng)用交互的。幸運的是,這三個競爭者提供了使用自定義信息填充HTML的方法,以便讓大伙們能夠享受時髦的Bootstrap 前端。
模板讓你能夠直接向頁面注入動態(tài)信息,而不是采用AJAX。你只需要一次請求就可以獲取整個頁面以及所有的動態(tài)數(shù)據(jù),這對用戶體驗來說是很好的。這對于手機網(wǎng)站來說尤其重要,因為一次請求花費的時間會更長。
所有的模板選項依賴于“上下文環(huán)境(context)”,其為模板轉(zhuǎn)換為HTML提供了動態(tài)信息。模板的最簡單的例子是填充已登錄用戶的名字以正確的迎接他們。也可以用AJAX獲取這種動態(tài)信息,但是用一整個調(diào)用來填寫用戶的名字有點過頭了,而同時模板又是這么的簡單。
5.1 Django
我們使用的例子正如寫的那么簡單,假設(shè)我們有一個包含了用戶名的funllname屬性的user對象。在Python中我們這樣向模板中傳遞當前用戶:
- def a_view(request):
- # get the logged in user
- # ... do more things
- return render_to_response(
- "view.html",
- {"user": cur_user}
- )
擁有這個模板的上下文很簡單,傳入一個Python對象的字典和模板使用的數(shù)據(jù)結(jié)構(gòu)?,F(xiàn)在我們需要在頁面上渲染他們的名字,以防頁面忘了他們是誰。
- {% if user %}
- You are logged in as {{ user.fullname }}
- {% endif %}
首先,你會注意到這個 {% if user %} 概念。在Django模板中, {% 用來控制循環(huán)和條件的聲明。這里的if user聲明是為了防止那些不是用戶的情況。匿名用戶不應(yīng)該在頁面頭部看到“你已經(jīng)登錄”的字樣。
在if塊內(nèi),你可以看到,包含名字非常的簡單,只要用{{}}包含著我們要插入的屬性就可以了。{{是用來向模板插入真實值的,如{{ user.fullname }}。
模板的另一個常用情況是展示一組物品,如一個電子商務(wù)網(wǎng)站的存貨清單頁面。
- def browse_shop(request):
- # get items
- return render_to_response(
- "browse.html",
- {"inventory": all_items}
- )
在模板中,我們使用同樣的{%來循環(huán)清單中的所有條目,并填入它們各自的頁面地址。
- {% for widget in inventory %}
- {{ widget.displayname }}
- {% endfor %}
為了做大部分常見的模板任務(wù),Django可以僅僅使用很少的結(jié)構(gòu)來完成目標,因此很容易上手。
5.2 Flask
Flask默認使用受Django啟發(fā)的Jinja2模板語言,但也可以配置來使用另一門語言。不應(yīng)該抱怨一個倉促的程序員分不清Django和Jinja模板。事實是,上面的Django例子在Jinja2也有效。為了不去重復(fù)相同的例子,我們來看下Jinja2比Django模板更具表現(xiàn)力的地方。
Jinja和Django模板都提夠了過濾的特性,即傳入的列表會在展示前通過一個函數(shù)。一個擁有博文類別屬性的博客,可以利用過濾特性,在一個用逗號分割的列表中展示博文的類別。
Categories: {{ post.categories|join:", " }} Categories: {{ post.categories|join(", ") }}
在Jinja模板語言中,可以向過濾器傳入任意數(shù)量的參數(shù),因為Jinja把它看成是 使用括號包含參數(shù)的Python函數(shù)的一個調(diào)用。Django使用冒號來分割過濾器的名字和過濾參數(shù),這限制了參數(shù)的數(shù)目只能為一。
Jinjia和Django的for循環(huán)有點類似。我們來看看他們的不同。在Jinjia2中,for-else-endfor結(jié)構(gòu)能遍歷一個列表,同時也處理了沒有項的情況。
- {% for item in inventory %}
{{ item.render() }}- {% else %}
No items found
Try another search, maybe?
- {% endfor %}
Django版的這個功能是一樣的,但是是用for-empty-endfor而不是for-else-endfor。
- {% for item in inventory %}
{{ item.render }}- {% empty %}
No items found
Try another search, maybe?
- {% endfor %}
除了語法上的不同,Jinja2通過執(zhí)行環(huán)境和高級特性提供了更多的控制。例如,它可以關(guān)閉危險的特性以安全的執(zhí)行不受信任的模板,或者提前編譯模板以確保它們的合法性。
5.3 Pyramid
與Flask類似,Pyramid支持多種模板語言(包括Jinja2和Mako),但是默認只附帶一個。Pyramid使用Chameleon,一個 ZPT (Zope Page Template) 模板語言的實現(xiàn)。我們來回頭看看***個例子,添加用戶的名字到網(wǎng)站的頂欄。Python代碼除了明確調(diào)用了render_template函數(shù)外其他看起來都差不多。
- @view_config(renderer='templates/home.pt')
- def my_view(request):
- # do stuff...
- return {'user': user}
但是我們的模板看起來有些不同。ZPT是一個基于XML得模板標準,所以我們使用了類XSLT語句來操作數(shù)據(jù)。
- tal:content="string:You are logged in as ${user.fullname}"
- class="col-md-2 whoami">
Chameleon對于模板操作有三種不同的命名空間。TAL(模板屬性語言)提供了基本的條件語句,字符串的格式化,以及填充標簽內(nèi)容。上面的例子只用了TAL來完成相關(guān)工作。對于更多高級任務(wù),就需要TALES和METAL。TALES( 模板屬性表達式語法的語言)提供了像高級字符串格式化,Python表達式評估,以及導(dǎo)入表達式和模板的表達式。
METAL(宏擴展模板屬性語言)是Chameleon模板***大的(和復(fù)雜的)一部分。宏是可擴展的,并能被定義為帶有槽且當宏被調(diào)用時可以被填充。
6. 利用框架行動起來
對于各個框架,我們將通過制作一個叫做wut4lunch的應(yīng)用來了解,這個應(yīng)用是告訴整個互聯(lián)網(wǎng)你午飯吃了什么的社交網(wǎng)絡(luò)。很自由的一個起始想法,完全可以隨意改變。應(yīng)用將有一個簡單的接口,允許用戶提交他們午飯的內(nèi)容,并看到其他用戶吃的什么的列表。主頁完成后將看起來像這樣。
6.1 使用Flask的Demo應(yīng)用
最短的實現(xiàn)用了34行Python代碼和一個22行的Jinja模板。首先,我們有些管理類的任務(wù)要做,比如初始化我們的應(yīng)用并拉近我們的ORM。
- from flask import Flask
- # For this example we'll use SQLAlchemy, a popular ORM that supports a
- # variety of backends including SQLite, MySQL, and PostgreSQL
- from flask.ext.sqlalchemy import SQLAlchemy
- app = Flask(__name__)
- # We'll just use SQLite here so we don't need an external database
- app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
- db = SQLAlchemy(app)
現(xiàn)在我們看下我們的模型,這將和另兩個樣例基本一樣。
- class Lunch(db.Model):
- """A single lunch"""
- id = db.Column(db.Integer, primary_key=True)
- submitter = db.Column(db.String(63))
- food = db.Column(db.String(255))
哇,相當簡單。最難的部分是找到合適的 SQLAlchemy數(shù)據(jù)類型,選擇數(shù)據(jù)庫中String域的長度。使用我們的模型也超級簡單,這在于我們將要看到 SQLAlchemy查詢語法。
構(gòu)建我們的提交表單也很簡單。在引入Flask-WTForms和正確的域類型后,你可以看到表單看起來有點像我們的模型。主要的區(qū)別在于新的提交按鈕和食物與提交者姓名域的提示。
應(yīng)用中的SECRET_KEY域是被WTForms用來創(chuàng)建CSRF符號的。它也被itsdangerous(Flask內(nèi)包含)用來設(shè)置cookies和其他數(shù)據(jù)。
- from flask.ext.wtf import Form
- from wtforms.fields import StringField, SubmitField
- app.config['SECRET_KEY'] = 'please, tell nobody'
- class LunchForm(Form):
- submitter = StringField(u'Hi, my name is')
- food = StringField(u'and I ate')
- # submit button will read "share my lunch!"
- submit = SubmitField(u'share my lunch!')
讓表單在瀏覽器中顯示意味著模板要有它。我們像下面那樣傳遞進去。
- from flask import render_template
- @app.route("/")
- def root():
- lunches = Lunch.query.all()
- form = LunchForm()
- return render_template('index.html', form=form, lunches=lunches)
好了,發(fā)生了什么?我們得到已經(jīng)用Lunch.query.all()提交的午餐列表,并實例化一個表單,讓用戶提交他們自己的美食之旅。為了簡化,變量使用相同的名字出入模板,但這不是必須的。
Wut 4 Lunch - What are people eating?
Wut4Lunch is the latest social network where you can tell all your friends
- about your noontime repast!
這就是模板的真實情況,我們在已經(jīng)吃過的午餐中循環(huán),并在
- 中展示他們。這幾乎與我們前面看到的循環(huán)例子一樣。
- {% for lunch in lunches %}
- {{ lunch.submitter|safe }} just ate {{ lunch.food|safe }}
- {% else %}
- Nobody has eaten lunch, you must all be starving!
- {% endfor %}
- What are YOU eating?
- {{ form.hidden_tag() }}
- {{ form.submitter.label }} {{ form.submitter(size=40) }}
- {{ form.food.label }} {{ form.food(size=50) }}
- {{ form.submit }}
模板的
表單被不同的語法渲染,我們需要人工在表單主體中添加CSRF token,但這些區(qū)別更多的是裝飾
6.3測試Pyramid版App
***,我們看看用Pyramid實現(xiàn)的同樣的程序。與Django和Flask的***不同是模板。只需要對Jinja2做很小的改動就足以解決我們在Django中的問題。這次不是這樣的,Pyramid的Chameleon模板的語法更容易讓人聯(lián)想到XSLT而不是別的。
- Nobody has eaten lunch, you must all be starving!
與Django模板類似,缺少for-else-endfor結(jié)構(gòu)使得邏輯稍微的更清晰了。這種情況下,我們以if-for 和 if-not-for 語句塊結(jié)尾以提供同樣的功能。使用{{或{%來控制結(jié)構(gòu)和條件的Django以及AngularJS類型的模板讓使用XHTML標簽的模板顯得很外行。
Chameleon模板類型的一大好處是你所選擇的編輯器可以正確的使語法高亮,因為模板是有些得XHTML。對于Django和Flask模板來說,你的編輯器需要能夠正確的支持這些模板語言高亮顯示。
- What are YOU eating?
- Name: ${form.text("submitter", size=40)}
- What did you eat? ${form.text("food", size=40)}


咨詢
建站咨詢