一步一步學(xué)Django文檔_第1頁
一步一步學(xué)Django文檔_第2頁
一步一步學(xué)Django文檔_第3頁
一步一步學(xué)Django文檔_第4頁
一步一步學(xué)Django文檔_第5頁
已閱讀5頁,還剩46頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

一步一步學(xué)Django第2頁第一講入門開篇Django是新近出來的Rails方式的web開發(fā)框架。在接觸Django之前我接觸過其它幾種Python下的webframework,但感覺Karrigell是最容易上手的。不過Django從我個人的感覺上來看,它的功能更強(qiáng)大,社區(qū)也很活躍,高手眾多,發(fā)展也是極為迅速。3

Django的入門體驗(yàn)但Django呢?如果說最簡單的web體驗(yàn)Hello,Django!如何寫呢?決不會象Karrigell那樣簡單,只從它提供的教程來看,你無法在安裝后非常Easy地寫出一個Hello,Django!的例子,因?yàn)橛幸幌盗械陌惭b和準(zhǔn)備工作要做。那么下面我把我所嘗試寫最簡單的Hello,Django!的例子寫出來。請注意,我測試時是在WindowsXP環(huán)境下進(jìn)行的。3.1

安裝pythonsetup.pyinstall參考文檔Djangoinstalled,一般地,Django安裝前還需要先安裝setuptools包??梢詮腜yPI上搜到。目前最新的版本是0.95版,可以從Django的主頁上面下載。如果你想從老的0.91遷移到最新版本,可以參閱RemovingTheMagic文檔。安裝后,建議檢查pythoninstalldir/Scripts目錄是否在你的PATH環(huán)境中,如果不在,建議將這個目錄設(shè)置到PATH中。因?yàn)槿绻悴捎脴?biāo)準(zhǔn)的Python安裝方法,那么Django會自動在Scripts目錄下安裝django-admin.py程序。這樣,一旦你設(shè)置了Scripts在PATH中,就可以在命令行下任何目錄中執(zhí)行django-admin.py了。3.2

生成項(xiàng)目目錄因?yàn)镵arrigell可直接開發(fā),因此放在哪里都可以。而Django是一個框架,它有特殊的配置要求,因此一般不需要手工創(chuàng)建目錄之類的工作,Django提供了django-admin.py可以做這件事。為使用django-admin.py,建議將Python的Scripts目錄加入到PATH環(huán)境變量中去。django-admin.pystartprojectnewtest這樣就在當(dāng)前目錄下創(chuàng)建了一個newtest目錄,進(jìn)去入可以看到有四個文件:這個newtest將是我們以后工作的目錄,許多講解都是基于這個目錄的。__init__.py表示這是一個Python的包manage.py提供簡單化的django-admin.py命令,特別是可以自動進(jìn)行DJANGO_SETTINGS_MODULES和PYTHONPATH的處理,而沒有這個命令,處理上面環(huán)境變量是件麻煩的事情settings.py它是django的配置文件uls.pyurl映射處理文件,Django的url映射是url對某個模塊方法的映射,目前不能自動完成在0.91版,django-admin.pystartproject會生成apps目錄。但0.95版之后已經(jīng)沒有了。雖然django-admin.py為我們生成了許多東西,而且這些東西在以后的開發(fā)中你都需要熟悉,但現(xiàn)在我們的目標(biāo)是最簡單的體驗(yàn),就認(rèn)為我們不需要知道它們都有什么用吧。項(xiàng)目創(chuàng)建好了,那么我們可以啟動服務(wù)器嗎?Django為了開發(fā)方便,自帶了一個用于開發(fā)的webserver。在0.91版,你需要至少修改一下settings.py中的DATABASE_ENGINE,如果你不改,那么Django會報(bào)錯。在0.95版之后,不再需要設(shè)置了。3.3.1

啟動webserver:別急呀,還沒看見Hello,Django!在哪里呢。是的,我只是想看一看,Django能否啟動。manage.pyrunserver#Uncommentthisforadmin: #(r'^admin/',include('django.contrib.admin.urls')),)上面的r'^$'是為了匹配空串,也就是形如:http://localhost:8000/。如果這時webserver已經(jīng)啟動了,那么直接刷新頁面就行了?,F(xiàn)在覺得Django是不是簡單多了,除了創(chuàng)建一個項(xiàng)目的操作,然后可能要修改兩個配置文件。4

結(jié)論Django本身的確是一種松散的框架組合,它既復(fù)雜又簡單。復(fù)雜是因?yàn)槿绻阆胧褂盟淖詣踊?、高級的功能你需要學(xué)習(xí)很多的東西,而且它的教程一上來就是以這種過于完整的例子進(jìn)行展示,自然會讓你覺得很麻煩。不過看了我的講解之后,是不是覺得還是挺簡單的。那么我們就先以無數(shù)據(jù)庫的方式進(jìn)行下去,一點(diǎn)點(diǎn)地發(fā)掘Django的功能特性吧。第二講生成一個webform做加法的簡單例子1

引言隨著學(xué)習(xí),我們的例子也開始復(fù)雜了,下一步我想實(shí)現(xiàn)一個簡單的web加法器。界面會是這樣:如何處理頁面表格提交的數(shù)據(jù),并且會對URLDispatch作更進(jìn)一步的解釋。2

創(chuàng)建add.py文件我們先創(chuàng)建一個add.py文件。(由于我們還沒有涉及到Django的模型,因此象add.py這樣的東西叫什么呢?還是稱其為View吧。因?yàn)樵赿jango中,View是用來顯示的,它代替了一般的MVC中的Control的作用,因?yàn)镈jango中不是MVC而是MTV(ModelTemplateView))fromdjango.httpimportHttpResponsetext="""<formmethod="post"action="/add/"><inputtype="text"name="a"value="%d">+<inputtype="text"name="b"value="%d"><inputtype="submit"value="="><inputtype="text"value="%d"></form>"""defindex(request):ifrequest.POST.has_key('a'):a=int(request.POST['a'])b=int(request.POST['b'])else:a=0b=0returnHttpResponse(text%(a,b,a+b))請注意action為/add/,在Django中鏈接后面一般都要有'/',不然有可能得不到POST數(shù)據(jù)。有關(guān)更詳細(xì)的關(guān)于常見問題可以參閱NewbieMistakes文檔。這里只有一個index方法。所有在view中的方法第一個參數(shù)都會由Django傳入request對象,它就是請求數(shù)據(jù)對象,它是由Django自動生成。其中有GET和POST屬性,分別保存兩種不同的提交方式的數(shù)據(jù),它們都可以象字典一樣工作。更多關(guān)于request的內(nèi)容參見Requestandresponseobjects文檔。那么我的想法就是:進(jìn)入頁面后(就是上面的效果),頁面上有兩個輸入文本框,一個是提交按鈕,一個是顯示結(jié)果的文本框。在兩個輸入文本框中輸入整數(shù),然后點(diǎn)擊提交("="號按鈕),將返回相同的頁面,但結(jié)果文本框中將顯示兩數(shù)相加的和。兩個輸入文本框分別定義為a和b。這里的邏輯就是:先判斷POST數(shù)據(jù)中是否有變量a,如果沒有則表示是第一次進(jìn)入,則a,b初始為0,然后返回頁面。如果有變量a,則計(jì)算結(jié)果,返回頁面。3

修改urls.py,增加add的url映射。fromdjango.conf.urls.defaultsimport*urlpatterns=patterns('',#Example:#(r'^testit/',include('newtest.apps.foo.urls.foo')),(r'^$','newtest.helloworld.index'),(r'^add/$','newtest.add.index'),#Uncommentthisforadmin:#(r'^admin/',include('django.contrib.admin.urls')),)4啟動server5在瀏覽器測試:http://localhost:8000/add,你會看到和我相似的界面,然后輸入整數(shù)試一試。6

補(bǔ)充說明在form中的method="post"。你當(dāng)然可以使用get,但是在Django的設(shè)計(jì)風(fēng)格中認(rèn)為,使用POST表示要對數(shù)據(jù)進(jìn)行修改,使用GET則只是獲取。Django提供了URLDispatch文檔,專門講解有關(guān)url映射的東西。其中有一部分是關(guān)于url的正則表達(dá)式解析的。原本我認(rèn)為象Karrigell中一樣,定義在form中的變量會自動映射為方法的參數(shù),但是我錯了。方法中的參數(shù)是從url中通過正則表達(dá)式解析出來的,或者是在url_conf(即urls.py文件)中指定的。因此它與Karrigell一點(diǎn)也不一樣。因此,如果你想從POST或GET數(shù)據(jù)中得到值,那么象我一樣去做好了。使用request.POST或request.GET或還有一個可以“統(tǒng)吃”的方法request.REQUEST,它們是一個字典數(shù)據(jù),使用起來也算方便。從這里我更想了解方法中參數(shù)的使用,當(dāng)然這個例子并沒有,有機(jī)會再使用吧。關(guān)于正則表達(dá)式解析參數(shù)在blog和rss中用得是非常多的。第三講使用Template的簡單例子1

引言從上一例我們看到,表格的生成是直接在index()函數(shù)中返回的HTML代碼,這種混合方式對于大型開發(fā)非常不好,下面我們就學(xué)習(xí)模板的使用。Django自帶有模板系統(tǒng),但你可以不使用它,只要在return前使用自已喜歡的模板系統(tǒng)進(jìn)行處理,然后返回即可。但Django自帶的模板系統(tǒng)有很多特點(diǎn),我不做過多的說明。我只是想使用它?,F(xiàn)在我的問題就是:我有一個通訊錄數(shù)據(jù),我想使用一個表格來顯示。為了方便,我們不需要使用數(shù)據(jù)庫,因此我把它存在view文件中。2

創(chuàng)建list.py#coding=utf-8fromdjango.shortcutsimportrender_to_responseaddress=[{'name':'張三','address':'地址一'},{'name':'李四','address':'地址二'}]defindex(request):returnrender_to_response('list.html',{'address':address})我使用了漢字,并且字符的編碼使用了utf-8,請注意,而且以后如果不特別注明,所有的帶漢字的文件,包括模板都將使用utf-8編碼。這里使用了一個新方法是render_to_response,它可以直接調(diào)用模板并返回生成好的文本。它接收兩個參數(shù),第一個是模板的文件名。在Django0.91中,模板文件都是以.html結(jié)尾的,并且使用時是不帶后綴的。但0.95版本取消了缺省模板后綴的設(shè)置,因此模板文件名必須是完整的,不再有默認(rèn)后綴了。第二個參數(shù)是一個字典,這里只有一個Key,名字是address,它的值是一個字典的列表。只要注意模板所接收的就是這樣的字典和包含字典的列表就行了。在0.91中render_to_response是在django.core.extensions中的,而到了0.92轉(zhuǎn)變?yōu)閐jango.shortcuts。3

在newtest中創(chuàng)建templates目錄:用來存放模板文件4

修改settings.pyTEMPLATE_DIRS=(#Putstringshere,like"/home/html/django_templates".#Alwaysuseforwardslashes,evenonWindows.'./templates',)如果有多個模板目錄,加進(jìn)去就行了。Django會按順序搜索的。Django還支持在App中定義一個templates目錄。這樣Django在啟動時會檢查所有安裝的的App的templates目錄,如果存在,則將路徑的搜索放在TEMPLATE_DIRS之后。這樣就可以很方便地管理你的模板了。5

創(chuàng)建templates/list.html<h2>通訊錄</h2><tableborder="1"><tr><th>姓名</th><th>地址</th></tr>{%foruserinaddress%}<tr><td>{{}}</td><td>{{user.address}}</td></tr>{%endfor%}</table>生成了一個兩列的表格。在Django模板中{{}}表示引用一個變量,{%%}表示代碼調(diào)用。在變量引用中,Django還支持對變量屬性的訪問,同時它還有一定的策略,詳細(xì)的建議查看TheDjangotemplatelanguage文檔。這里我也使用了漢字,因此它也需要使用utf-8編碼。這里使用for..in的模板Tag處理。因此address需要是一個集合。在我們的View代碼中,address為一個list值。每個list又是一個字典。因此{(lán){}}和{{user.address}}就是將此字典中的元素取出來。后面我們將了解更多的模板中的Tag標(biāo)簽的使用。且你會發(fā)現(xiàn),Django中的Tag很強(qiáng)大,可通過擴(kuò)展形成龐大的Tag庫方便模板的開發(fā)。6

修改urls.py增加了list的url映射。fromdjango.conf.urls.defaultsimport*urlpatterns=patterns('',#Example:#(r'^testit/',include('newtest.apps.foo.urls.foo')),(r'^$','newtest.helloworld.index'),(r'^add/$','newtest.add.index'),(r'^list/$','newtest.list.index'),#Uncommentthisforadmin:#(r'^admin/',include('django.contrib.admin.urls')),)7

啟動server::8000/list,效果如這樣:第四講生成csv格式文件并下載1

引言經(jīng)過前幾節(jié)的學(xué)習(xí),我想大家應(yīng)該比較熟悉Django的大致開發(fā)流程了:增加view方法增加模板修改urls.py剩下的就是挖掘Django提供的其它的能力。在我們還沒有進(jìn)入模型(model)之前還是再看一看外圍的東西,再更進(jìn)一步體驗(yàn)Django吧。在Django中我看到了一個生成csv格式的文檔(OutputtingCSVdynamically),非常好,它沒有數(shù)據(jù)庫,正好用來做演示。現(xiàn)在我的需求就是提供csv格式文件的下載。我們會在原來list(表格)例子基礎(chǔ)上進(jìn)行演示,步驟就是上面的流程。2

修改templates/list.html在文件最后增加:<p><ahref="/csv/address/">csv格式下載</a></p>它將顯示為一個鏈接,它所指向的鏈接將用來生成csv文件。3

在newtest下增加csv_test.py#coding=utf-8fromdjango.httpimportHttpResponsefromdjango.templateimportloader,Contextaddress=[('張三','地址一'),('李四','地址二')]defoutput(request,filename):response=HttpResponse(mimetype='text/csv')response['Content-Disposition']='attachment;filename=%s.csv'%filenamet=loader.get_template('csv.html')c=Context({'data':address,})response.write(t.render(c))returnresponseloader,Context是從django.core.template導(dǎo)入的,而0.95為django.template。具體可以參考:NamespaceSimplification文檔。以后類似的地方不再詳述。這里使用的東西多了一些。這里沒有render_to_response了,而是演示了一個完整的從頭進(jìn)行模板解析的處理過程。為什么需要這樣,因?yàn)槲覀冃枰薷膔esponse對象的值,而render_to_response封裝了它使得我們無法修改。從這里我們也可以看到,在調(diào)用一個方法時,Django會傳入一個request對象,在返回時,你需要將內(nèi)容寫入response,必要時修改它的某些屬性。更詳細(xì)的建議你參考django所帶的request_response文檔,里面詳細(xì)描述了兩個對象的內(nèi)容,并且還可以在交互環(huán)境下進(jìn)行測試,學(xué)習(xí)非常方便。response對象也是由Django自動維護(hù)的。具體的內(nèi)容參見Requestandresponseobjects文檔。這里address不再是字典的列表,而是tuple的列表。讓人高興的是,Django的模板除了可以處理字典,還可以處理序列,而且可以處理序列中的元素。一會在模板定義中我們會看到。這里output()是我們希望Django調(diào)用的方法,不再是index()了。而且它與前面的index()不同,它帶了一個參數(shù)。這里主要是想演示url的參數(shù)解析。因此你要注意,這個參數(shù)一定是放在url上的。它表示輸出文件名。response=HttpResponse(mimetype='text/csv')response['Content-Disposition']='attachment;filename=%s.csv'%filename這兩行是用來處理輸出類型和附件的。它表明返回的是一個csv格式的文件。t=loader.get_template('csv.html')c=Context({'data':address,})response.write(t.render(c))這幾行就是最原始的模板使用方法。先通過loader來找到需要的模板,然后生成一個template對象,再生成一個Context對象,它就是一個字典集。然后t.render(c)這個用來對模板和提供的變量進(jìn)行合并處理,生成最終的結(jié)果。最后調(diào)用response.write()將內(nèi)容寫入。4

增加templates/csv.html{%forrowindata%}"{{row.0|addslashes}}","{{row.1|addslashes}}",{%endfor%}使用了一個for循環(huán)。這里data與上面的Context的data相對應(yīng)。因?yàn)閐ata是一個列表,它的每行是一個tuple,因此row.0,row.1就是取tuple的第一個和第二個元素。|是一個過濾符,它表示將前一個的處理結(jié)果作為輸入傳入下一個處理。因此Django的模板很強(qiáng)大,使用起來也非常直觀和方便。addslashes是Django模板內(nèi)置的過濾Tag,它用來將結(jié)果中的特殊字符加上反斜線。同時我們注意到,每個{{}}前后都有一個雙引號,這樣就保證每個字符串使用雙引號引起來。然后在第一個與第二個元素之間還使用了逗號分隔。最后endfor在下一行,表示上面每行模板后有一個回車。Django還允許你自定義Tag,在TheDjangotemplatelanguage:ForPythonprogrammers文檔中有描述。5

修改urls.pyfromdjango.conf.urls.defaultsimport*urlpatterns=patterns('',#Example:#(r'^testit/',include('newtest.apps.foo.urls.foo')),(r'^$','newtest.helloworld.index'),(r'^add/$','newtest.add.index'),(r'^list/$','newtest.list.index'),(r'^csv/(?P<filename>\w+)/$','newtest.csv_test.output'),#Uncommentthisforadmin:#(r'^admin/',include('django.contrib.admin.urls')),)增加了csv的url映射。上面的正則表達(dá)式有些復(fù)雜了,因?yàn)橛袇?shù)的處理在里面。(?P<filename>\w+)這是一個將解析結(jié)果起名為filename的正則表達(dá)式,它完全符合Python正則表達(dá)式的用法。在最新的Django中,還可以簡化一下:(\w+)。但這樣需要你的參數(shù)是按順序傳入的,在一個方法有多個參數(shù)時一定要注意順序。關(guān)于url的配置問題在URLconfiguration文檔中有說明。還記得嗎?我們的鏈接是寫成/csv/address/,因此上面實(shí)際上會變成對csv.output(filename='address')的調(diào)用。6

啟動server:看一下結(jié)果吧。點(diǎn)擊鏈接,瀏覽器會提示你保存文件的。很簡單吧。但這里面的內(nèi)容其實(shí)也不少,而且許多地方都有很大的擴(kuò)展空間。第五講session和數(shù)據(jù)庫1

引言現(xiàn)在我們就學(xué)習(xí)一下session吧。session可以翻譯為“會話”,做過web的可能都知道。它就是為了實(shí)現(xiàn)頁面間的數(shù)據(jù)交換而產(chǎn)生的東西,一般有一個session_id,它會保存在瀏覽器的cookie中,因此如果你的瀏覽器禁止了cookie,下面的試驗(yàn)是做不了的。在Django中的session也非常簡單,它就存在于request對象的session屬性中。你可以把它看成一個字典就可以了。下面我們做一個非常簡單的功能:首先當(dāng)用戶進(jìn)入某個頁面,這個頁面會顯示一個登錄頁面,上面有一個文本框用來輸入用戶名,還有一個提交按鈕用來提交數(shù)據(jù)。當(dāng)用戶輸入用戶名,然后點(diǎn)提交,則顯示用戶已經(jīng)登錄,并且打印出用戶的姓名來,同時還提供一個“注銷”按鈕。然后如果用戶再次進(jìn)入這個頁面,則顯示同登錄成功后的頁面。如果點(diǎn)擊注銷則重新進(jìn)入未登錄的頁面。2

在newtest下創(chuàng)建login.pyfromdjango.httpimportHttpResponseRedirectfromdjango.shortcutsimportrender_to_responsedeflogin(request):username=request.POST.get('username',None)ifusername:request.session['username']=usernameusername=request.session.get('username',None)ifusername:returnrender_to_response('login.html',{'username':username})else:returnrender_to_response('login.html')deflogout(request):try:delrequest.session['username']exceptKeyError:passreturnHttpResponseRedirect("/login/")兩個方法:login()和logout()。login()用來提供初始頁面、處理提供數(shù)據(jù)和判斷用戶是否登錄。而logout()只是用來從session中刪除用戶名,同時將頁面重定向到login畫面。這里我仍然使用了模板,并且根據(jù)傳入不同的字典來控制模板的生成。是的,因?yàn)镈jango的模塊支持條件判斷,所以可以做到。在login()中的判斷邏輯是:先從POST中取username(這樣username需要由模板的form來提供),如果存在則加入到session中去。加入session很簡單,就是一個字典的Key賦值。然后再從session中取username,有兩種可能:一種是上一步實(shí)現(xiàn)的。還有一種可能是直接從以前的session中取出來的,它不是新產(chǎn)生的。而這里并沒有細(xì)分這兩種情況。因此這個判斷其實(shí)對應(yīng)兩種頁面請求的處理:一種是提交了用戶姓名,而另一種則是處理完用戶提交姓名之后,用戶再次進(jìn)入的情況。而用戶再次進(jìn)入時,由于我們在前面已經(jīng)將他的名字保存在session里面了,因此可以直接取出來。如果session中存在,則表示用戶已經(jīng)登錄過,則輸出login.html模板,同時傳入了username字典值。而如果session中不存在,說明用戶從來沒有登錄過,則輸出login.html模板,這次不帶值。 因此對于同一個login.html模板傳入的不同值,后面我們會看到模板是如何區(qū)分的。在logout()中很簡單。先試著刪除session,然后重定向頁面到login頁面。這里使用了HttpResponseRedirect方法,它是從以前我們看到的HttpResponse派生來的子類。更多的派生子類和關(guān)于response的內(nèi)容要參考Requestandresponseobjects文檔。3

創(chuàng)建templates/login.html{%ifnotusername%}<formmethod="post"action="/login/">用戶名:<inputtype="text"name="username"value=""><br/><inputtype="submit"value="登錄"></form>{%else%}你已經(jīng)登錄了!{{username}}<br/><formmethod="post"action="/logout/"><inputtype="submit"value="注銷"></form>{%endif%}整個是一個if語句。在Django模板中的if可以象Python一樣使用,如使用not,and,or。象ifnotusername表示什么呢?它表示如果username不存在,或?yàn)榭?,或是假值等等。而此時我們利用了username不存在這種判斷。上面的邏輯表示,如果username不存在,則顯示一個表單,顯示用戶名輸入文本框。如果存在,則顯示已經(jīng)登錄信息,同時顯示用戶名和注銷按鈕。而這個注銷銨鈕對應(yīng)于logout()方法。4

修改urls.py:增加了login和logout兩個url映射。fromdjango.conf.urls.defaultsimport*urlpatterns=patterns('',#Example:#(r'^testit/',include('newtest.apps.foo.urls.foo')),(r'^$','newtest.helloworld.index'),(r'^add/$','newtest.add.index'),(r'^list/$','newtest.list.index'),(r'^csv/(?P<filename>\w+)/$','newtest.csv_test.output'),(r'^login/$','newtest.login.login'),(r'^logout/$','newtest.login.logout'),#Uncommentthisforadmin: #(r'^admin/',include('django.contrib.admin.urls')),)5

啟動server運(yùn)行但我要說,你一定會報(bào)錯。而且我的也在報(bào)錯。從這一刻起,我們就要進(jìn)入有數(shù)據(jù)庫的環(huán)境了。因?yàn)樵赿jango中session是存放在數(shù)據(jù)庫中的。所以在這里要進(jìn)行數(shù)據(jù)庫的初始化了。6

修改settings.py,主要修改以下地方:DATABASE_ENGINE='sqlite3'DATABASE_NAME='./data.db'DATABASE_USER=''DATABASE_PASSWORD=''DATABASE_HOST=''DATABASE_PORT=''這里我使用sqlite3。在使用數(shù)據(jù)庫時,需要安裝相應(yīng)的數(shù)據(jù)庫處理模塊。對sqlite3只需要修改兩項(xiàng):DATABASE_ENGINE和DATABASE_NAME。這里數(shù)據(jù)文件名我使用了相對路徑,在實(shí)際情況下可能使用絕對路徑為好。sqlite3對應(yīng)的是pysqlite2模塊,從/下載到最新版本。如果你使用utf-8,要注意缺省字符編碼應(yīng)為utf-8。同時對于DATABASE_PORT字段,Django目前允許使用數(shù)字或字符串表示了。7

初始化數(shù)據(jù)庫:改了配置還不夠,還要執(zhí)行相應(yīng)的建庫、建表的操作,使用django-admin.py或manage.py都可以:manage.pysyncdb它可以自動創(chuàng)建已經(jīng)安裝的App中,在數(shù)據(jù)庫中不存在的Model。并且會自動將表的權(quán)限賦與超級用戶。并且把超級用戶的創(chuàng)建也結(jié)合到了一起。8

啟動server,這次再進(jìn)入試吧:http://localhost:8000/login/,從此我們要進(jìn)入數(shù)據(jù)庫的世界了,當(dāng)然目前還沒有用到,而Django提供的許多自動化的高級功能都是需要數(shù)據(jù)庫支持的。第六講wiki的例子1

引言以后的例子可能會越來越復(fù)雜,下面我們按照TurboGears的20MinuteWikiTutorial的例子仿照一個,我們要用Django來做wiki。我不會按TurboGears的操作去做,只是實(shí)現(xiàn)一個我認(rèn)為的最簡單的wiki?,F(xiàn)在我的要求是:做一個簡單的wiki,要可以修改當(dāng)前頁面,即在頁面下面提供一個編輯的按鈕。然后還要識別頁面中的兩個開頭大寫的單詞為頁面切換點(diǎn),可以進(jìn)入一個已經(jīng)生成好的頁面,或提示創(chuàng)建一個新頁面。下面我們將開始創(chuàng)建Django中的app了。先說一下。如果你看過官方版的教程,它就是講述了一個Poll的app的生成過程。那么一個app就是一個功能的集合,它有自已的model,view和相應(yīng)的模板,還可以帶自已的urls.py。那么它也是一個獨(dú)立的目錄,這樣一個app就可以獨(dú)立地進(jìn)行安裝,你可以把它安裝到其它的Django服務(wù)器中去。因此采用app的組織形式非常有意義。而且adango-admin.py也提供了一個針對app的命令,一會我們就會看到。而且Django提供一些自動功能也完全是針對于app這種結(jié)構(gòu)的。Model,Template,View就合成了MTV這幾個字母。Model是用來針對數(shù)據(jù)庫,同時它可以用來自動生成管理界面,View在前面我們一直都用它,用來處理請求和響應(yīng)的相當(dāng)于MVC框架中的Controller的作用,Template用來生成界面。2

創(chuàng)建wikiappmanage.pystartappwiki在0.91版,app都是放在apps目錄下的。不過到了0.95版,apps目錄不自動創(chuàng)建了。因此你就可以直接放在項(xiàng)目目錄下了。這樣在wiki子目錄下有以下文件:__init__.py表示wiki目錄是一個包。views.py用來放它的view的代碼。models.py用來放model代碼。3

編輯wiki/models.pyfromdjango.dbimportmodels#Createyourmodelshere.classWiki(models.Model):pagename=models.CharField(max_length=20,unique=True)content=models.TextField()每個model其實(shí)在Django中就是一個表,你將用它來保存數(shù)據(jù)。在實(shí)際的應(yīng)用中,一般都要與數(shù)據(jù)庫打交道,如果不想用數(shù)據(jù)庫,那么原因可能就是操作數(shù)據(jù)庫麻煩,創(chuàng)建數(shù)據(jù)庫環(huán)境也麻煩。但通過Django的model處理,它是一種ORM(ObjectRelationMapping,對象與關(guān)系的映射),可以屏蔽掉底層數(shù)據(jù)庫的細(xì)節(jié),同時提供以對象的形式來處理數(shù)據(jù)。非常方便。而且Django的model層支持多種數(shù)據(jù)庫,如果你改變數(shù)據(jù)庫不是問題,這也為以后的數(shù)據(jù)庫遷移帶來好處。Wiki是model的名字,它需要從models.Model派生而來。它定義了兩個字段,一個是字段是pagename,用來保存wiki頁面的名字,它有兩個參數(shù),一個是最大長度(從這點(diǎn)上不如SQLAlchemy方便,SQLAlchemy并不需要長度,它會根據(jù)有無長度自動轉(zhuǎn)為TEXT類型),目前CharField需要這個參數(shù);另一個是unique表示這個字段不能有重復(fù)值。還有一個字段是content,用來保存wiki頁面的內(nèi)容,它是一個TextField類型,它不需要最大長度。在運(yùn)行時,Django會自動地為這個model增加許多數(shù)據(jù)操作的方法。關(guān)于model和數(shù)據(jù)庫操作API的詳細(xì)內(nèi)容參見Modelreference和DatabaseAPIreference的文檔。4

修改settings.py,安裝app雖然我們的其它工作沒有做完,但我還是想先安裝一下app吧。每個app都需要安裝一下。安裝一般有兩步:修改settings.pyINSTALLED_APPS=('django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.sites','newtest.wiki',)執(zhí)行(在newtest目錄下)manage.pysyncdb以前是使用installwiki?,F(xiàn)在也可以使用,不過使用syncdb要更簡單得多。如果沒有報(bào)錯就是成功了。這一步Django將根據(jù)model的信息在數(shù)據(jù)庫中創(chuàng)建相應(yīng)的表。5

在命令行下加入首頁(FrontPage)我們假設(shè)首頁的名字為FrontPage,并且我們將在命令行下增加它,讓我們熟悉一下命令行的使用,進(jìn)入newtest目錄,然后:manage.pyshell進(jìn)入python>>>fromnewtest.wiki.modelsimportWiki>>>page=Wiki(pagename='FrontPage',content='WelcometoEasyWiki')>>>page.save()>>>Wiki.objects.all()[<Wikiobject>]>>>p=Wiki.objects.all()[0]>>>p.pagename'FrontPage'>>>p.content'WelcometoEasyWiki'因?yàn)樵趯戇@篇教程時是在magic-removal分枝下進(jìn)行的操作,因此有些API并不穩(wěn)定。象objects的方法以前是沿用model的方法,但后來進(jìn)行了簡化,比如get_list()變?yōu)閍ll()。還有一系統(tǒng)的變化。具體的可參見RemovingTheMagic文檔中關(guān)于Descriptorfields的說明。在Django中,對于數(shù)據(jù)庫的記錄有兩種操縱方式,一種是集合方式,一種是對象方式。集合方式相當(dāng)于表級操作,在0.92中可以使用model.objects來處理。objects對象有一些集合方式的操作,如all()會返回全部記錄,filter()會根據(jù)條件返回部分記錄。而象插入新記錄則需要使用記錄方式來操作。6

修改wiki/views.py#coding=utf-8fromnewtest.wiki.modelsimportWikifromdjango.templateimportloader,Contextfromdjango.httpimportHttpResponse,HttpResponseRedirectfromdjango.shortcutsimportrender_to_responsedefindex(request,pagename=""):"""顯示正常頁面,對頁面的文字做特殊的鏈接處理"""ifpagename:#查找是否已經(jīng)存在頁面#pages=Wiki.objects.get_list(pagename__exact=pagename)pages=Wiki.objects.filter(pagename=pagename)ifpages:#存在則調(diào)用頁面模板進(jìn)行顯示returnprocess('wiki/page.html',pages[0])else:#不存在則進(jìn)入編輯畫面returnrender_to_response('wiki/edit.html',{'pagename':pagename})else:#page=Wiki.objects.get_object(pagename__exact='FrontPage')page=Wiki.objects.get(pagename='FrontPage')returnprocess('wiki/page.html',page)defedit(request,pagename):"""顯示編輯存在頁面"""#page=Wiki.objects.get_object(pagename__exact=pagename)page=Wiki.objects.get(pagename=pagename)returnrender_to_response('wiki/edit.html',{'pagename':pagename,'content':page.content})defsave(request,pagename):"""保存頁面內(nèi)容,老頁面進(jìn)行內(nèi)容替換,新頁面生成新記錄"""content=request.POST['content']#pages=Wiki.objects.get_list(pagename__exact=pagename)pages=Wiki.objects.filter(pagename=pagename)ifpages:pages[0].content=contentpages[0].save()else:page=Wiki(pagename=pagename,content=content)page.save()returnHttpResponseRedirect("/wiki/%s"%pagename)importrer=pile(r'\b(([A-Z]+[a-z]+){2,})\b')defprocess(template,page):"""處理頁面鏈接,并且將回車符轉(zhuǎn)為<br>"""t=loader.get_template(template)content=r.sub(r'<ahref="/wiki/\1">\1</a>',page.content)content=re.sub(r'[\n\r]+','<br>',content)c=Context({'pagename':page.pagename,'content':content})returnHttpResponse(t.render(c))將原來老的model方法加了注釋,目前改用最新的API了。代碼有些長,有些地方已經(jīng)有說明和注釋了。簡單說一下:index()用來顯示一個wiki頁面。它需要一個參數(shù)就是頁面的名稱。如果在數(shù)據(jù)庫中找得到,則調(diào)用process()方法(process()方法是一個自定義方法,主要用來對頁面的文本進(jìn)行處理,比如查找是否有滿足wiki命名規(guī)則的單詞,如果有則替換成鏈接。再有就是將回車轉(zhuǎn)為<br>)。如果沒有找到,則直接調(diào)用編輯模板顯示一個編程頁面。當(dāng)然,這個頁面的內(nèi)容是空的。只是它的頁面名字就是pagename。如果pagename為空,則進(jìn)入FrontPage頁面。Wiki.objects對象有filter()方法和get()方法,一個返回一個結(jié)果集,一個返回指定的對象。這里為什么使用filter()呢,因?yàn)橐坏┲付ㄎ募淮嬖?,它并不是返回一個None對象,而是拋出異常,而我沒有使用異常的處理方式。通過filter()如果存在則結(jié)果中應(yīng)有一個元素,如果不存在則應(yīng)該是一個[]。這樣就知道是否有返回了。filter()中使用的參數(shù)與一般的db-api是一樣的,但如果是比較相等,可以為:pagename__exact=pagename也可以簡化為pagename=pagename。在Django中,一些字段的比較操作比較特殊,它是在字段名后加__然后是比較條件。這樣看上去就是一個字符串。具體的參見TheDatabaseAPI。回車轉(zhuǎn)換的工作其實(shí)可以在模板中使用filter來完成。從對模板的使用(wiki/edit.html)可以猜到在后面我們要在templates中創(chuàng)建子目錄了。的確,對于不同的app,我們可以考慮將所有的模板都放在統(tǒng)一的templates目錄下,但為了區(qū)分方便,一般都會針對app創(chuàng)建不同的子目錄。當(dāng)然也可以不這樣,可以放在其它的地方,只要修改settings.py,將新的模板目錄加進(jìn)去就行了。因?yàn)槲覀冊谠O(shè)計(jì)model時已經(jīng)設(shè)置了pagename必須是唯一的,因此一旦filter()有返回值,那它只能有一個元素,而pages[0]就是我們想要的對象。page=wikis.get(pagename='FrontPage'),是表示取出pagename為FrontPage的頁面。你可能要說,為什么沒有異常保護(hù),是的,這也就是為什么我們要在前面先要插條記錄在里面的原因。這樣就不會出錯了。再加上我要做的wiki不提供刪除功能,因此不用擔(dān)心會出現(xiàn)異常。edit()用來顯示一個編輯頁面,它直接取出一個頁面對象,然后調(diào)用wiki/edit.html模板進(jìn)行顯示。也許你還是要問,為什么不考慮異常,因?yàn)檫@里不會出現(xiàn)。為什么?因?yàn)閑dit()只用在已經(jīng)存在的頁面上,它將用于存在頁面的修改。而對于不存在的頁面是在index()中直接調(diào)用模板來處理,并沒有直接使用這個edit()來處理。也許你認(rèn)為這樣可能不好,但由于在edit()要重新檢索數(shù)據(jù)庫,而在index()已經(jīng)檢索過一次了,沒有必要再次檢索,因此象我這樣處理也沒什么不好,效率可能要高一些。當(dāng)然這只是個人意見。save()用來在編輯頁面時用來保存內(nèi)容的。它先檢查頁面是否在數(shù)據(jù)庫中存在,如果不存在則創(chuàng)建一個新的對象,并且保存。注意,在Django中,對對象處理之后只有調(diào)用它的save()方法才可以真正保存到數(shù)據(jù)庫中去。如果頁面已經(jīng)存在,則更新頁面的內(nèi)容。處理之后再重定向到index()去顯示這個頁面。7

在templates中創(chuàng)建wiki子目錄8

編輯templates/wiki/page.html<h2>{{pagename}}</h2><p>{{content}}</p><hr/><p><formmethod="POST"action="/wiki/{{pagename}}/edit/"><inputtype="submit"value="編輯"></form></p>它用來顯示頁面,同時提供一個“編輯”按鈕。當(dāng)點(diǎn)擊這個按鈕時將調(diào)用view中的edit()方法。9

編輯templates/wiki/edit.html<h2>編輯:{{pagename}}</h2><formmethod="POST"action="/wiki/{{pagename}}/save/"><textareaname="content"rows="10"cols="50">{{content}}</textarea><br/><inputtype="submit"value="保存"></form>它用來顯示一個編輯頁面,同時提供“保存”按鈕。點(diǎn)擊了保存按鈕之后,會調(diào)用view中的save()方法。10

修改urls.pyfromdjango.conf.urls.defaultsimport*urlpatterns=patterns('',#Example:#(r'^testit/',include('newtest.apps.foo.urls.foo')),(r'^$','newtest.helloworld.index'),(r'^add/$','newtest.add.index'),(r'^list/$','newtest.list.index'),(r'^csv/(?P<filename>\w+)/$','newtest.csv_test.output'),(r'^login/$','newtest.login.login'),(r'^logout/$','newtest.login.logout'),(r'^wiki/$','newtest.wiki.views.index'),(r'^wiki/(?P<pagename>\w+)/$','newtest.wiki.views.index'),(r'^wiki/(?P<pagename>\w+)/edit/$','newtest.wiki.views.edit'),(r'^wiki/(?P<pagename>\w+)/save/$','newtest.wiki.views.save'),#Uncommentthisforadmin:#(r'^admin/',include('django.contrib.admin.urls')),)增加了wiki等4個url映射。一般一個wiki,我們訪問它的一個頁面可能為:wiki/pagename。我設(shè)計(jì)對index()方法的調(diào)用的url為:r'^wiki/(?P<pagename>\w+)/$'也就是把wiki/后面的解析出來作為pagename參數(shù)。但這樣就帶來一個問題,如果我想實(shí)現(xiàn)wiki/edit.html表示修改,pagename作為一個參數(shù)通過POST來提交好象就不行了。因?yàn)樯厦娴慕馕鲆?guī)則會“吃”掉這種情況。因此我采用Zope的表示方法:把對象的方法放在對象的后面。我可以把pagename看成為一個對象,edit,save是它的方法,放在它的后面,也簡單,也清晰。當(dāng)然如果我們加強(qiáng)上面的正則表達(dá)式,也可以解析出wiki/edit.html的情況。因此wiki/pagename就是顯示一個頁面,wiki/pagename/edit就是編輯這個頁面,wiki/pagename/save就是保存頁面。而pagename解析出來后就是分別與index(),edit(),save()的pagename參數(shù)相對應(yīng)。下面你可以運(yùn)行了。11

啟動server:manage.pyrunserver,進(jìn)入http://localhost:8000/wiki首先進(jìn)入這個頁面:然后你點(diǎn)編輯,則進(jìn)入FrontPage的編輯界面:然后我們加上一個TestPage,它符合wiki的名字要求,兩個首字母大寫的單詞連在一起。然后點(diǎn)擊保存??匆娏税?。頁面上的TestPage有了鏈接。點(diǎn)擊它將進(jìn)入:這是TestPage的編輯頁面。讓我們輸入中文,然后輸入FrontPage。然后保存。好了,剩下的你來玩吧。點(diǎn)擊FrontPage將回到首頁。第七講通訊錄1

引言敢問路在何方,路在腳下。如果你堅(jiān)持下來,一定會有收獲的。直到目前我們已經(jīng)學(xué)了:settings.py的設(shè)置urldispatcher模板sessionappmodel其實(shí)在某些方面,使用Django還可以更加方便。而且我們還有許多東西沒有學(xué),一點(diǎn)點(diǎn)跟著我學(xué)吧。我有一個通訊錄,它是保存在Excel文件中的,我不想每次到目錄下去打開它,我希望用Django做一個web上的簡單應(yīng)用,如何做呢?2

創(chuàng)建addressappmanage.pystartappaddress;這樣就創(chuàng)建好了address相關(guān)的目錄了。\l

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論