Pyramid, Django, 和 Flask都是優(yōu)秀的框架,為項目選擇其中的哪一個都是傷腦筋的事。我們將會用三種框架實現(xiàn)相同功能的應(yīng)用來更容易的對比三者。也可以直接跳到框架實戰(zhàn)(Frameworks in Action)章節(jié)查看代碼(code)。世界上可選的基于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的模塊拉進(jìn)箱子中。Django包括一個開箱即用的 ORM ,而Pyramid和 Flask讓開發(fā)者自己選擇如何或者是否存儲他們的數(shù)據(jù)。到目前為止對于非Django的web應(yīng)用來說最流行的ORM是SQLAlchemy,同時還有多種其他選擇,從 DynamoDB和MongoDB 到簡單本地存儲的LevelDB 或樸實的SQLite。Pyramid被設(shè)計為可使用任何數(shù)據(jù)持久層,甚至是還沒有開發(fā)出來的。Django的”batteries included” 特性讓開發(fā)者不需要提前為他們的應(yīng)用程序基礎(chǔ)設(shè)施做決定,因為他們知道Python已經(jīng)深入到了web應(yīng)用當(dāng)中。Django已經(jīng)內(nèi)建了模板、表單、路由、認(rèn)證、基本數(shù)據(jù)庫管理等等。比較起來,Pyramid包括路由和認(rèn)證,但是模板和數(shù)據(jù)庫管理需要額外的庫。前面為 Flask和Pyramid apps選擇組件的額外工作給那些使用案例不適用標(biāo)準(zhǔn)ORM的開發(fā)者提供了更多的靈活性,同樣也給使用不同工作流和模版化系統(tǒng)的開發(fā)者們帶來了靈活性。Flask,作為三個框架里面最稚氣的一個,開始于2010年年中。Pyramid框架是從Pylons項目開始的,在2010年底獲得 Pyramid這個名字,雖然在2005年就已經(jīng)發(fā)布了第一個版本。Django 2006年發(fā)布了第一個版本,就在Pylons項目(最后叫Pyramid)開始之后。Pyramid和Django都是非常成熟的框架,積累了眾多插件和擴(kuò)展以滿足難以置信的巨大需求。雖然Flask歷史相對更短,但它能夠?qū)W習(xí)之前出現(xiàn)的框架并且把注意力放在了微小項目上。它大多數(shù)情況被使用在一些只有一兩個功能的小型項目上。例如 httpbin,一個簡單的(但很強(qiáng)大的)調(diào)試和測試HTTP庫的項目。最具活力的社區(qū)當(dāng)屬Django,其有80,000個StackOverflow問題和一系列來自開發(fā)者和優(yōu)秀用戶的良好的博客。Flask和Pyramid社區(qū)并沒有那么大,但它們的社區(qū)在郵件列表和IRC上相當(dāng)活躍。StackOverflow上僅有5,000個相關(guān)的標(biāo)簽,F(xiàn)lask比Django小了15倍。在Github上,它們的star近乎相當(dāng),Django有11,300個,F(xiàn)lask有10,900個。三個框架都使用的是BSD衍生的協(xié)議。Flask和Django的協(xié)議是BSD 3條款,Pyramid的Repoze Public License RPL是BSD協(xié)議 4條款的衍生。Django和Pyramid都內(nèi)建bootstrapping工具。Flask沒有包含類似的工具,因為Flask的目標(biāo)用戶不是那種試圖構(gòu)建大型MVC應(yīng)用的人。Flask的hello world應(yīng)用非常的簡單,僅僅單個Python文件的7行代碼就夠了。# from http://flask./ tutorialfrom flask import Flaskapp = Flask(__name__) @app.route("/") # take note of this decorator syntax, it's a common patterndef 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)用的需求。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非常靈活. 不局限于一個默認(rèn)的程序;pcreate 可以使用任意數(shù)量的項目模版. 包括我們上面用到的pcreate里面的”starter”的模版, 還有 SQLAlchemy- ,ZODB-支持scaffold項目. 在 PyPi可以發(fā)現(xiàn)已經(jīng)為Google App Engine, jQuery Mobile, Jinja2 templating, modern frontend frameworks做好的scaffolds, 還有更多~
Django 也有自己的 bootstrap 工具, 內(nèi)置在 django-admin 中.django-admin startproject hello_djangodjango-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, 不過在默認(rèn)配置中只能有一個.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 默認(rèn)只在項目中創(chuàng)建 空白的 model 和模板文件, 供新手參考的示范代碼不多. 此外, 開發(fā)者在發(fā)布應(yīng)用程序的時候, 還要自己配置, 這也是個麻煩.bootstrap 工具的缺點是沒有指導(dǎo)開發(fā)者如何打包應(yīng)用. 對于那些沒有經(jīng)驗的新手來說, 第一次部署應(yīng)用將是個很頭疼的問題. 像 django-oscar 這樣的大社區(qū), 項目都是打包好了, 放在 PyPi 上供大家安裝. 但是 Github 上面的小項目缺少統(tǒng)一的打包方式.一個Python應(yīng)用能夠響應(yīng)HTTP請求將是一個偉大的開端,但是有可能你的大多數(shù)用戶是沒有興趣使用curl與你的web應(yīng)用交互的。幸運的是,這三個競爭者提供了使用自定義信息填充HTML的方法,以便讓大伙們能夠享受時髦的Bootstrap 前端。模板讓你能夠直接向頁面注入動態(tài)信息,而不是采用AJAX。你只需要一次請求就可以獲取整個頁面以及所有的動態(tài)數(shù)據(jù),這對用戶體驗來說是很好的。這對于手機(jī)網(wǎng)站來說尤其重要,因為一次請求花費的時間會更長。所有的模板選項依賴于“上下文環(huán)境(context)”,其為模板轉(zhuǎn)換為HTML提供了動態(tài)信息。模板的最簡單的例子是填充已登錄用戶的名字以正確的迎接他們。也可以用AJAX獲取這種動態(tài)信息,但是用一整個調(diào)用來填寫用戶的名字有點過頭了,而同時模板又是這么的簡單。我們使用的例子正如寫的那么簡單,假設(shè)我們有一個包含了用戶名的funllname屬性的user對象。在Python中我們這樣向模板中傳遞當(dāng)前用戶: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)在我們需要在頁面上渲染他們的名字,以防頁面忘了他們是誰。<!-- view.html --><div class="top-bar row"> <div class="col-md-10"> <!-- more top bar things go here --> </div> {% if user %} <div class="col-md-2 whoami"> You are logged in as {{ user.fullname }} </div> {% endif %}</div>
首先,你會注意到這個 {% 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 %}
<li><a href="/widget/{{ widget.slug }}/">{{ widget.displayname }}</a></li>
{% endfor %}
為了做大部分常見的模板任務(wù),Django可以僅僅使用很少的結(jié)構(gòu)來完成目標(biāo),因此很容易上手。
Flask默認(rèn)使用受Django啟發(fā)的Jinja2模板語言,但也可以配置來使用另一門語言。不應(yīng)該抱怨一個倉促的程序員分不清Django和Jinja模板。事實是,上面的Django例子在Jinja2也有效。為了不去重復(fù)相同的例子,我們來看下Jinja2比Django模板更具表現(xiàn)力的地方。Jinja和Django模板都提夠了過濾的特性,即傳入的列表會在展示前通過一個函數(shù)。一個擁有博文類別屬性的博客,可以利用過濾特性,在一個用逗號分割的列表中展示博文的類別。<!-- Django --><div class="categories">Categories: {{ post.categories|join:", " }}</div> <!-- now in Jinja --><div class="categories">Categories: {{ post.categories|join(", ") }}</div>
在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 %}<div class="display-item">{{ item.render() }}</div>{% else %}<div class="display-warn"><h3>No items found</h3><p>Try another search, maybe?</p></div>{% endfor %}
Django版的這個功能是一樣的,但是是用for-empty-endfor而不是for-else-endfor。{% for item in inventory %}<div class="display-item">{{ item.render }}</div>{% empty %}<div class="display-warn"><h3>No items found</h3><p>Try another search, maybe?</p></div>{% endfor %}
除了語法上的不同,Jinja2通過執(zhí)行環(huán)境和高級特性提供了更多的控制。例如,它可以關(guān)閉危險的特性以安全的執(zhí)行不受信任的模板,或者提前編譯模板以確保它們的合法性。與Flask類似,Pyramid支持多種模板語言(包括Jinja2和Mako),但是默認(rèn)只附帶一個。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得模板標(biāo)準(zhǔn),所以我們使用了類XSLT語句來操作數(shù)據(jù)。<div class="top-bar row"> <div class="col-md-10"> <!-- more top bar things go here --> </div> <div tal:condition="user" tal:content="string:You are logged in as ${user.fullname}" class="col-md-2 whoami"> </div></div>
Chameleon對于模板操作有三種不同的命名空間。TAL(模板屬性語言)提供了基本的條件語句,字符串的格式化,以及填充標(biāo)簽內(nèi)容。上面的例子只用了TAL來完成相關(guān)工作。對于更多高級任務(wù),就需要TALES和METAL。TALES( 模板屬性表達(dá)式語法的語言)提供了像高級字符串格式化,Python表達(dá)式評估,以及導(dǎo)入表達(dá)式和模板的表達(dá)式。METAL(宏擴(kuò)展模板屬性語言)是Chameleon模板最強(qiáng)大的(和復(fù)雜的)一部分。宏是可擴(kuò)展的,并能被定義為帶有槽且當(dāng)宏被調(diào)用時可以被填充。對于各個框架,我們將通過制作一個叫做wut4lunch的應(yīng)用來了解,這個應(yīng)用是告訴整個互聯(lián)網(wǎng)你午飯吃了什么的社交網(wǎng)絡(luò)。很自由的一個起始想法,完全可以隨意改變。應(yīng)用將有一個簡單的接口,允許用戶提交他們午飯的內(nèi)容,并看到其他用戶吃的什么的列表。主頁完成后將看起來像這樣。最短的實現(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 PostgreSQLfrom flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__)# We'll just use SQLite here so we don't need an external databaseapp.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))
哇,相當(dāng)簡單。最難的部分是找到合適的 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 Formfrom 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!')
讓表單在瀏覽器中顯示意味著模板要有它。我們像下面那樣傳遞進(jìn)去。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()提交的午餐列表,并實例化一個表單,讓用戶提交他們自己的美食之旅。為了簡化,變量使用相同的名字出入模板,但這不是必須的。<html>
<title>Wut 4 Lunch</title>
<b>What are people eating?</b>
<p>Wut4Lunch is the latest social network where you can tell all your friends
about your noontime repast!</p>
這就是模板的真實情況,我們在已經(jīng)吃過的午餐中循環(huán),并在<ul>中展示他們。這幾乎與我們前面看到的循環(huán)例子一樣。<ul>{% for lunch in lunches %}<li><strong>{{ lunch.submitter|safe }}</strong> just ate <strong>{{ lunch.food|safe }}</strong>{% else %}<li><em>Nobody has eaten lunch, you must all be starving!</em></li>{% endfor %}</ul> <b>What are YOU eating?</b> <form method="POST" action="/new"> {{ form.hidden_tag() }} {{ form.submitter.label }} {{ form.submitter(size=40) }} <br/> {{ form.food.label }} {{ form.food(size=50) }} <br/> {{ form.submit }}</form></html>
模板的<form>部分僅僅渲染我們在root()視圖中傳入模板的WTForm對象的表單標(biāo)簽和輸入。當(dāng)表單提交時,它將向/new提交一個POST請求,這個請求會被下面的函數(shù)處理。from flask import url_for, redirect @app.route(u'/new', methods=[u'POST'])def newlunch(): form = LunchForm() if form.validate_on_submit(): lunch = Lunch() form.populate_obj(lunch) db.session.add(lunch) db.session.commit() return redirect(url_for('root'))
在驗證了表單數(shù)據(jù)后,我們把內(nèi)容放入我們Model對象中,并提交到數(shù)據(jù)庫。一旦我們在數(shù)據(jù)庫中存了午餐,它將在人們吃過的午餐列表中出現(xiàn)。if __name__ == "__main__": db.create_all() # make our sqlalchemy tables app.run()
最后,我們只需做(非常)少量的工作來讓應(yīng)用運行起來。使用SQLAlchemy,我們可以創(chuàng)建存儲午餐的表,然后開始運行我們寫的路徑管理就行了。Django版wut4lunch 和Flask版有點像,但是在Django項目中被分到了好幾個文件中。首先,我們看看最相似的部分:數(shù)據(jù)庫模型。它和SQLAlchemy版本的唯一不同之處是聲明保存文本的數(shù)據(jù)庫字段有輕微的語法區(qū)別。# from wut4lunch/models.pyfrom django.db import models class Lunch(models.Model): submitter = models.CharField(max_length=63) food = models.CharField(max_length=255)
在表單系統(tǒng)上。不像Flask,我們可以用Django內(nèi)建的表單系統(tǒng)。它看起來非常像我們在Flask中使用的WTFroms模塊,只是語法有點不同。from django import forms
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .models import Lunch
# Create your views here.
class LunchForm(forms.Form):
"""Form object. Looks a lot like the WTForms Flask example"""
submitter = forms.CharField(label='Your name')
food = forms.CharField(label='What did you eat?')
現(xiàn)在我們只需要構(gòu)造一個LunchForm實例傳遞到我們的模板。lunch_form = LunchForm(auto_id=False) def index(request): lunches = Lunch.objects.all() return render( request, 'wut4lunch/index.html', { 'lunches': lunches, 'form': lunch_form, } )
render函數(shù)是Django shortcut,以接受請求、模板路徑和一個上下文的dict。與Flask的render_template類似,它也接受接入請求。def newlunch(request): l = Lunch() l.submitter = request.POST['submitter'] l.food = request.POST['food'] l.save() return redirect('home')
保存表單應(yīng)答到數(shù)據(jù)庫是不一樣的,Django調(diào)用模型的 .save()方法以及處理會話管理而不是用全局?jǐn)?shù)據(jù)庫會話。干凈利落!Django提供了一些優(yōu)雅的特性,讓我們管理用戶提交的午餐,因此我們可以刪除那些不合適的午餐信息。Flask和Pyramid沒有自動提供這些功能,而在創(chuàng)建一個Django應(yīng)用時不需要寫另一個管理頁面當(dāng)然也是其一個特性。開發(fā)者的時間可不免費??!我們所要做的就是告訴Django-admin我們的模型,是在wut5lunch/admin.py中添加兩行。from wut4lunch.models import Lunchadmin.site.register(Lunch)
Bam?,F(xiàn)在我們可以添加刪除一些條目,而無需額外的工作。
<ul>{% for lunch in lunches %}<li><strong>{{ lunch.submitter }}</strong> just ate <strong>{{ lunch.food }}</strong></li>{% empty %}<em>Nobody has eaten lunch, you must all be starving!</em>{% endfor %}</ul>
Django擁有方便的快捷方式,在你的頁面中引用其他的視圖。url標(biāo)簽可以使你重建應(yīng)用中的URLs,而不需破壞視圖。這個是因為url標(biāo)簽會主動查詢視圖中的URL。<form action="{% url 'newlunch' %}" method="post"> {% csrf_token %} {{ form.as_ul }} <input type="submit" value="I ate this!" /></form>
表單被不同的語法渲染,我們需要人工在表單主體中添加CSRF token,但這些區(qū)別更多的是裝飾最后,我們看看用Pyramid實現(xiàn)的同樣的程序。與Django和Flask的最大不同是模板。只需要對Jinja2做很小的改動就足以解決我們在Django中的問題。這次不是這樣的,Pyramid的Chameleon模板的語法更容易讓人聯(lián)想到XSLT而不是別的。<!-- pyramid_wut4lunch/templates/index.pt -->
<div tal:condition="lunches">
<ul>
<div tal:repeat="lunch lunches" tal:omit-tag="">
<li tal:content="string:${lunch.submitter} just ate ${lunch.food}"/>
</div>
</ul>
</div>
<div tal:condition="not:lunches">
<em>Nobody has eaten lunch, you must all be starving!</em>
</div>
與Django模板類似,缺少for-else-endfor結(jié)構(gòu)使得邏輯稍微的更清晰了。這種情況下,我們以if-for 和 if-not-for 語句塊結(jié)尾以提供同樣的功能。使用{{或{%來控制結(jié)構(gòu)和條件的Django以及AngularJS類型的模板讓使用XHTML標(biāo)簽的模板顯得很外行。
Chameleon模板類型的一大好處是你所選擇的編輯器可以正確的使語法高亮,因為模板是有些得XHTML。對于Django和Flask模板來說,你的編輯器需要能夠正確的支持這些模板語言高亮顯示。<b>What are YOU eating?</b> <form method="POST" action="/newlunch"> Name: ${form.text("submitter", size=40)} <br/> What did you eat? ${form.text("food", size=40)} <br/> <input type="submit" value="I ate this!" /></form></html>
Pyramid中表單得轉(zhuǎn)換稍微更細(xì)致些,因為pytamid_simpleform不像Django表單的form.as_ul函數(shù)那樣可以自動轉(zhuǎn)換所有的表單字段。現(xiàn)在我們看看什么返回給應(yīng)用。首先,定義我們需要得表單并呈現(xiàn)我們的主頁。# pyramid_wut4lunch/views.pyclass LunchSchema(Schema): submitter = validators.UnicodeString() food = validators.UnicodeString() @view_config(route_name='home', renderer='templates/index.pt')def home(request): lunches = DBSession.query(Lunch).all() form = Form(request, schema=LunchSchema()) return {'lunches': lunches, 'form': FormRenderer(form)}
獲取午餐的查詢語法和Flask的很相似,這是因為這兩個demo應(yīng)用使用了流行的SQLAlchemy ORM來提供持久存儲。在Pyramid中,允許你直接返回模板上下文的字典,而不是要調(diào)用特殊的render函數(shù)。@view_config裝飾器自動將返回的上下文傳入要渲染的模板。避免調(diào)用render方法使得Pyramid寫的函數(shù)更加容易測試,因為它們返回的數(shù)據(jù)沒有被模板渲染對象掩蓋。@view_config(route_name='newlunch', renderer='templates/index.pt', request_method='POST')def newlunch(request): l = Lunch( submitter=request.POST.get('submitter', 'nobody'), food=request.POST.get('food', 'nothing'), ) with transaction.manager: DBSession.add(l) raise exc.HTTPSeeOther('/')
從Pyramid的請求對象中更加容易得到表單數(shù)據(jù),因為在我們獲取時會自動將表單POST數(shù)據(jù)解析成dict。為了阻止同一時間多并發(fā)的請求數(shù)據(jù)庫,ZopeTransactions模塊提供了上下文管理器,對寫入邏輯事物的數(shù)據(jù)庫進(jìn)行分組,并阻止應(yīng)用的線程在各個改變時互相影響,這在你的視圖共享一個全局session并接收到大量通信的情況下將會是個問題。Pyramid是三個中最靈活的。它可以用于小的應(yīng)用,正如我們所見,但它也支撐著有名的網(wǎng)站如Dropbox。開源社區(qū)如Fedora選擇它開發(fā)應(yīng)用,如他們社區(qū)中的徽章系統(tǒng),從項目工具中接受事件的信息,并向用戶獎勵成就類型的徽章。對于Pyramid的一個最常見的抱怨是,它提供了這么多的選項,以至于用它開始一個新項目很嚇人。目前最流行的框架是Django,使用它的網(wǎng)站列表也令人印象深刻。Bitbucket,Pinterest,Instagram,以及Onion完全或部分使用Django。對于有常見需求的網(wǎng)站,Django是非常理智的選擇,也因此它成為中大型網(wǎng)站應(yīng)用的流行選擇。Flask對于那些開發(fā)小項目、需要快速制作一個簡單的Python支撐的網(wǎng)站的開發(fā)者很有用。它提供小型的統(tǒng)一工具,或者在已有的API上構(gòu)建的簡單網(wǎng)絡(luò)接口??梢钥焖匍_發(fā)需要簡單web接口并不怎么配置的后端項目使用Flask將會在前端獲益,如jitviewer提供了一個web接口來檢測PyPy just-in-time的編譯日志。這三個框架都能解決我們簡單的需求,我們已經(jīng)看到了它們的不同。這些區(qū)別不僅僅是裝飾性的,它們將會改變你設(shè)計產(chǎn)品的方法,以及添加新特性和修復(fù)的速度。因為我們的例子很小,我們看到Flask的閃光點,以及Django在小規(guī)模應(yīng)用上的笨重。Pyramid的靈活并未體現(xiàn)出來,因為我們的要求是一樣的,但在真實場景中,新的需求會常常出現(xiàn)。來源:www.oschina.net/translate/django-flask-pyramid