(7)Django框架學習-Views,URLconf的進階用法篇


Views,URLconf的advanced用法

之前有介紹了一些views和路徑匹配的基礎用法,在這里介紹一些關於它們的advanced用法。

URLconf技巧

因為urls.py也是一個python文件,所以你可以在這個文件中使用python允許的任何語法。
先看之前介紹的例子:
from django.conf.urls import patterns, include, url
from books.views import hello, search_form, search, contact, thanks

urlpatterns = patterns( '',
    url(r '^hello/$', hello),
    url(r '^search/$', search),
    url(r '^contact/$', contact),
    url(r '^contact/thanks/$', thanks),
)
每一個路徑匹配需要導入相應的模塊,所以當app的規范越來越大的時候,第二行的import語句
就越長。。。所以可以采用以下幾種方法來必定:
1. 只import到模塊就可以了,不用寫出函數
from django.conf.urls import patterns, include, url
from books import views
urlpatterns = patterns( '',
    url(r '^hello/$', views.hello),
    url(r '^search/$', views. search),
    url(r '^contact/$', views.contact),
    url(r '^contact/thanks/$', views.thanks),
)
2. 使用字符串來代表需要執行的views函數,這里就需要寫全路徑
from django.conf.urls import patterns, include, url

urlpatterns = patterns( '',
    url(r '^hello/$', 'books.views.hello'),
    url(r '^search/$', 'books.views.search'),
    url(r '^contact/$', 'books.views.contact'),
    url(r '^contact/thanks/$', 'books.views.thanks'),
)
3. 更簡單的字符串寫法,需要使用到patterns()的第一個參數
from django.conf.urls import patterns, include, url

urlpatterns = patterns( 'books.views',
    url(r '^hello/$', 'hello'),
    url(r '^search/$', 'search'),
    url(r '^contact/$', 'contact'),
    url(r '^contact/thanks/$', '    thanks'),
)
以上的方法都是合法的,具體看你選擇了。
 
因為patterns()返回的對象可以進行加法,當遇到多個views模塊的路徑前綴時,可以使用如下方式
來統一管理你的路徑匹配:
from django.conf.urls import patterns, include, url

urlpatterns = patterns( 'books.views',
    url(r '^hello/$', 'hello'),
    url(r '^search/$', 'search'),
    url(r '^contact/$', 'contact'),
    url(r '^contact/thanks/$', '    thanks'),
)

urlpatterns += patterns( 'weblogs.views',
    url(r '^hello/$', 'world'),
)

使用正規表達式的組操作來向views傳遞參數

正則表達式可以使用()來表示匹配成功的組,同時可以使用后向引用\1,\2...\n來表示不同的組,
在表達式中代表重復的匹配字串。
不用groups的話,返回的一個match對象。
 
在python中還可以為組命名,使用(?P<year>\d{4}),意思是這個組的名字為year,匹配的是4個數字
正因為有命名組和不命名組的這兩種使用,正好可以以兩種方式給view函數傳遞參數:
1. 不命名組以順序的方式傳值
# views.py
def count( self, a, b) :
    ....
#urls.py
(r '^num/(\d{4})/(\d{2})/$', count),
#結果
#對於請求/num/1234/78,產生的調用為count(1234, 78)
2. 命名組以字典的方式傳值
#urls.py
(r '^num/(?P<b>\d{4})/(?P<a>\d{2})/$', count),
#結果
#對於請求/num/1234/78,產生的調用為count(b=1234, a=78)
通過比較,使用命名組有更大的優勢,可以讓代碼一目了然,也不用擔心參數的順序搞錯。
還是最好不用混用命名組和非命名組,雖然Django不會報錯,但不太好,你懂的。
 
下面了解一下url匹配的過程:
1. 如果含有命名組,優先采用字典參數
2. 其余的非命名組將會以順序的方式傳遞到剩余的參數中
3. url中其它的選項,將會以字典的方式傳遞
#urls.py
urlpatterns = patterns( '',
     #第三個選項值可用來傳遞一些附加信息,同時可以讓請求路徑簡潔一點
     #否則有時候請求鏈接帶太多參數也不太好
    (r '^foo/(?P<a>\d{2})$', count, { 'b' : 43}),
)
#結果
#對於請求/num/12,產生的調用為count(12, b=43)
當然,view的函數可以使用默認值,這樣,如果請求路徑中沒有匹配到值的話,會調用默認的值。
注意,一般來說默認值應該設置為字符串,這樣是和請求路徑匹配過來的值的類型保持一致。因為
它們都是字符串。 即使你匹配的是數學,傳入的還是數字的字符串,需要使用int()函數進行轉化成
真正的整數。
 

在這里復習一下,django到底會匹配請求路徑的哪一部分?

1. 給定請求路徑www.example.com/myapp/foo
只會匹配myapp/foo這個部分
 
2. 給定請求路徑www.example.com/myapp/foo?name=david
只會匹配myapp/foo這個部分
 
3. 給定請求路徑www.example.com/myapp/foo#name=david
只會匹配myapp/foo這個部分
 
請求路徑中也不會包含請求GET還是POST,任何匹配成功的請求,都會運行同一個函數,
但這樣做不太好,最好還是對GET和POST采用不同的處理,這里就要用到request對象,
之前也介紹過,它包含了豐富的信息。
def foo(request) :
     if request.method == 'POST' :
         #handle post ...
         #need to redirect
         return HttpResponseRedirect( '/someurl/')
     elif request.method == 'GET' :
         #handle get
         #just return response
         return render_to_response( 'page.html')

通過路徑匹配動態構造view中的函數

上代碼:
#views.py
def say_hello( self, person_name) :
     print 'Hello, %s' % person_name

def say_goodbye( self, person_name) :
     print 'Goodbye, %s' % person_name
#urls.py
urlpatterns = patterns( '',
    (r '^say_hello/(\w+)$', say_hello),
    (r '^say_goodbye/(\w+)/$', say_goodbye),
)
上面兩個函數基本是做同一件事,傳入一個人的名字,然后問候一句。
所以稍微改動一下匹配規則,創建一個動態處理這兩件事的一個函數。
#views.py
def greet( self, person_name, greeting) :
     print '%s, %s' % person_name

#urls.py
urlpatterns = patterns( '',
    (r '^say_hello/(\w+)$', greet, { 'greeting' : 'Hello'}),
    (r '^say_goodbye/(\w+)/$', greet, { 'greeing' : 'Goodbye'}),
)
可以看到url中的第三個選項值可以傳入額外的信息,保持請求路徑的簡潔。
同時,這個選項值還可以傳入model類,使用委托的方式,讓你的view函數功能更加動態。
還可以傳入模塊名稱,讓你不用把模塊名寫死在render_to_response函數中。
 
還有一點需要注意,當命名組的名字和第三個選項值的名字相同時,Django會使用第三個選項值,
因為它的優先級更高。

使用閉包和可變長度參數來重構views函數

這里要用的概念有:
1. 函數對象也可以當參數進行傳遞
2. 閉包,可以簡單的理解為是函數中定義函數
3. 參數中*args代表可變長度元組參數,也叫非關鍵字參數,**args代表可變長度字典類參數,也叫關鍵字參數
注意報錯內容,關鍵字參數一定要放在最右邊
 
重構例子:
def my_view1(request) :
     if not request.user.is_authenticated() :
         return HttpResponseRedirect( '/accounts/login/')
     # ...
     return render_to_response( 'template1.html')

def my_view2(request) :
     if not request.user.is_authenticated() :
         return HttpResponseRedirect( '/accounts/login/')
     # ...
     return render_to_response( 'template2.html')

def my_view3(request) :
     if not request.user.is_authenticated() :
         return HttpResponseRedirect( '/accounts/login/')
     # ...
     return render_to_response( 'template3.html')
#這上面三個方法,一開始都要進行驗證,這有點重復
#下面添加一個新的方法
def requires_login(view) :
     def new_view(request, *args, **kwargs) :
         if not request.user.is_authenticated() :
             return HttpResponseRedirect( '/accounts/login/')
         return view(request, *args, **kwargs)
     return new_view
#使用閉包,定義相同的驗證的部分,並返回相應的函數對象,這樣就可以
#在上面三個函數中實現自己不同的代碼了。可以把驗證的部分統統去掉。
#另外urls.py可以改成
from django.conf.urls.defaults import *
from mysite.views import requires_login, my_view1, my_view2, my_view3

urlpatterns = patterns( '',
    (r '^view1/$', requires_login(my_view1)),
    (r '^view2/$', requires_login(my_view2)),
    (r '^view3/$', requires_login(my_view3)),
)

使用include()引用其它路徑配置文件

from django.conf.urls.defaults import *

urlpatterns = patterns( '',
    (r '^weblog/', include( 'mysite.blog.urls')),
    (r '^photos/', include( 'mysite.photos.urls')),
    (r '^about/$', 'mysite.views.about'),
)
一個project有一個總的urls.py,各個app也可以自己建立自己的urls.py,不過都需要使用include()
函數在project的urls.py文件進行注冊。這樣利用你的項目管理。
 
可以注意到使用了include的路徑的匹配表達式沒有加上'$',這是因為Django的機制是
把當前匹配的請求路徑的部分去除,剩下的部分傳到include所指定的路徑配置中進行匹配。
比如一個請求路徑/weblog/7000/過來,匹配部分是weblog/7000/,又因為weblog/匹配成功,
就把剩余的部分7000/傳入到mysit.blog.urls文件中進行下一步的匹配。
 
當使用include()的路徑匹配中含有正則組的時候,這個匹配的參數會傳入對include中所指定的urlconf中
所有的函數里,不管函數是接受這個參數,顯然很容易報錯,所以這種做法不太好。
 
同理,如果你在include的路徑匹配中使用了第三個選項參數,也會強制傳入指定的urlconf中的所有函數中。
也不太好。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM