亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python探索之URL Dispatcher實(shí)例詳解

 更新時(shí)間:2017年10月28日 10:45:51   作者:hackerain  
這篇文章主要介紹了Python探索之URL Dispatcher實(shí)例詳解,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。

URL dispatcher簡(jiǎn)單點(diǎn)理解就是根據(jù)URL,將請(qǐng)求分發(fā)到相應(yīng)的方法中去處理,它是對(duì)URL和View的一個(gè)映射,它的實(shí)現(xiàn)其實(shí)也很簡(jiǎn)單,就是一個(gè)正則匹配的過(guò)程,事先定義好正則表達(dá)式和該正則表達(dá)式對(duì)應(yīng)的view方法,如果請(qǐng)求的URL符合這個(gè)正則表達(dá)式,那么就分發(fā)這個(gè)請(qǐng)求到這個(gè)view方法中。

有了這個(gè)base,我們先拋出幾個(gè)問(wèn)題,提前思考一下:

這個(gè)映射定義在哪里?當(dāng)映射很多時(shí),如果有效的組織?

URL中的參數(shù)怎么獲取,怎么傳給view方法?

如何在view或者是template中反解出URL?

好,先來(lái)看一個(gè)簡(jiǎn)單的例子:

from django.conf.urls import patterns, url, include
urlpatterns = patterns('',
  url(r'^articles/2003/$', 'news.views.special_case_2003'),
  url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
)
urlpatterns += patterns('',
  url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
  url(r'model/', include('model_test.urls')),
)

這段代碼就是一個(gè)URL Dispatcher的例子,它在一個(gè)單獨(dú)的python模塊定義,Django中管這個(gè)模塊叫做URLconf,其實(shí),就是通過(guò)python代碼方式實(shí)現(xiàn)的配置文件,在這個(gè)配置中定義了URL路徑和對(duì)應(yīng)的處理方法之間的映射。在Django中,是通過(guò)“樹(shù)”的結(jié)構(gòu)來(lái)管理URLconf之間的關(guān)系的,在Django中的主配置文件中,有一個(gè)叫做ROOT_URL_CONF的配置項(xiàng),就是用來(lái)指定根URLconf,從根URLconf開(kāi)始,逐條進(jìn)行匹配,直到找到匹配項(xiàng)為止,這就是我們上面提到的第一個(gè)問(wèn)題的答案,下面還會(huì)再仔細(xì)剖析。

在上面例子中,我們可以看到有3個(gè)方法:patterns, url, include。url方法構(gòu)建了一個(gè)URL到View方法的映射關(guān)系對(duì)象,patterns將這些映射關(guān)系對(duì)象組織成為一個(gè)python的列表,那include是做什么的呢?它就是我們上面說(shuō)到的“樹(shù)”結(jié)構(gòu)關(guān)系的聯(lián)系者,include會(huì)關(guān)聯(lián)其他的URLconf到本URLconf,也就是說(shuō)include關(guān)聯(lián)的是孩子節(jié)點(diǎn)。整個(gè)URL dispatcher體系,就是由這三個(gè)方法構(gòu)建起來(lái)的,下面我們重點(diǎn)來(lái)介紹這三個(gè)方法,了解了這三個(gè)方法,整個(gè)URL映射機(jī)制就會(huì)非常清楚了。

def patterns(prefix, *args):
  pass
def url(regex, view, kwargs=None, name=None, prefix=''):
  pass
def include(arg, namespace=None, app_name=None):
  pass

url()

先來(lái)看下最重要的url()方法。第一個(gè)參數(shù)regex是代表URL的正則表達(dá)式,第二個(gè)參數(shù)指定了和該正則表達(dá)式映射的View,此外,還可以通過(guò)kwargs參數(shù),給view方法指定默認(rèn)的kwargs參數(shù),還有name參數(shù),用來(lái)命名該URL,主要用在URL反解中,至于prefix用處不大,不解釋。

url()方法最終構(gòu)造了一個(gè)對(duì)象,我們姑且叫它URL映射對(duì)象,當(dāng)?shù)谝淮卧L問(wèn)這個(gè)對(duì)象去匹配URL時(shí),它會(huì)把這個(gè)對(duì)象中的正則表達(dá)式編譯一次,然后保存在該對(duì)象中,所以以后再次匹配時(shí),就會(huì)很快,不會(huì)重復(fù)編譯該正則表達(dá)式了。在這里正則匹配其實(shí)就是用就是python的re模塊,使用過(guò)程大致如下:

# 第一次訪問(wèn)時(shí),編譯,然后保存在url對(duì)象中
regex = re.compile(regex_str, re.UNICODE)
# 每次URL訪問(wèn)時(shí),進(jìn)行正則匹配
match = regex.search(path)
kwargs = match.groupdict()
args = match.groups()

注意,這里涉及到了上面提到的第二個(gè)問(wèn)題,即URL中的參數(shù)是如何獲取,如何傳遞給view方法的。從URL中獲取參數(shù),其實(shí)是通過(guò)re模塊中named groups和non-named groups的概念來(lái)獲取的,通過(guò)match.groupdict()得到的是named groups,其實(shí)就是一個(gè)字典,字典的key是在URL中指定的,該字典會(huì)作為kwargs參數(shù)傳遞給view,而通過(guò)match.groups()得到的是non-named groups,是一個(gè)元組,即tuple,該元組會(huì)作為args參數(shù)傳遞給view。不過(guò),這里的args和kwargs是不能夠同時(shí)存在的,當(dāng)有kwargs不為空時(shí),args就會(huì)被置空,當(dāng)kwargs為空時(shí),args才會(huì)被用到,而傳遞給view的kwargs就只有url()方法中指定的默認(rèn)kwargs。也就是說(shuō),如果你在URL中使用了named groups,那么non-named groups就會(huì)被忽略,如果只使用了non-named groups,它才會(huì)被作為args參數(shù),傳遞給view方法。

好,糾結(jié)了一大堆,還是來(lái)解析一下我們上面提到的例子,假如我們有url和view

urls:

url(r'^articles/(\d{4})/$', 'news.views.year_archive')
url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive')

views:

def year_archive(request, *args, **kwargs):
  pass
def month_archive(request, *args, **kwargs):
  pass

當(dāng)我們?cè)L問(wèn)”articles/2014/”這個(gè)路徑的時(shí)候,解析的過(guò)程如下:

>>> import re
>>> regex = re.compile(r'^articles/(\d{4})/$', re.UNICODE)
>>> match = regex.search("articles/2014/")
>>> match.groupdict()
{}
>>> match.groups()
('2014',)

所以最終傳遞給year_archive()方法中的參數(shù)應(yīng)該是這樣的:

(Pdb) pp args
(u'2014',)
(Pdb) pp kwargs
{}

當(dāng)我們?cè)L問(wèn)”articles/2014/11”這個(gè)路徑時(shí),解析的過(guò)程如下:

>>> import re
>>> regex = re.compile(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', re.UNICODE)
>>> match = regex.search("articles/2014/11/")
>>> match.groupdict()
{'year': '2014', 'month': '11'}
>>> match.groups()
('2014', '11')

所以最終傳遞給month_archive()方法中的參數(shù)應(yīng)該是這樣的:

(Pdb) pp args
()
(Pdb) pp kwargs
{'month': u'11', 'year': u'2014'}

再羅嗦一句,因?yàn)閡rl()可以指定一個(gè)kwargs參數(shù),它是該url關(guān)聯(lián)的view()方法的默認(rèn)kwargs參數(shù),也就是說(shuō)如果在url()方法中指定了kwargs,那么會(huì)將這個(gè)參數(shù)的內(nèi)容,也傳遞到view方法中的kwargs參數(shù)中。

好,至此,url()方法基本上就清楚了,第二個(gè)問(wèn)題也解決了,至于name參數(shù),到下面講到URL反解的時(shí)候再詳細(xì)解釋。

patterns()

接下來(lái),我們來(lái)看patterns()方法,這個(gè)其實(shí)比較簡(jiǎn)單,它就是返回一個(gè)由url()方法構(gòu)造的URL映射對(duì)象組成的列表。它有一個(gè)必填參數(shù)是prefix,這個(gè)prefix是它所包含的view的公共前綴,這么做是為了避免代碼重復(fù),比如:

urlpatterns = patterns('',
  url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
  url(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
  url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

可以寫成:

urlpatterns = patterns('news.views',
  url(r'^articles/(\d{4})/$', 'year_archive'),
  url(r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
  url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
)

注意,由patterns()生成的列表,被賦值給urlpatterns這個(gè)變量,這個(gè)變量是不能隨便定義的,必須是約定好的,默認(rèn)django會(huì)去URLconf中查找這個(gè)變量,也許你可以在某個(gè)地方設(shè)定一個(gè)參數(shù),來(lái)?yè)Q個(gè)約定,改變一下這個(gè)變量名。

在2.0版本的Django中,會(huì)舍棄這個(gè)方法,而是直接賦值給urlpatterns一個(gè)列表,不做過(guò)多討論。

include()

我們來(lái)說(shuō)include(),這其實(shí)是個(gè)難點(diǎn),關(guān)鍵在于URL反解那里,Django的文檔也沒(méi)有說(shuō)清楚,而且關(guān)系也比較亂,所以,必須得實(shí)際的測(cè)試一下,才會(huì)明白。

上面說(shuō)過(guò),include()是“樹(shù)”結(jié)構(gòu)關(guān)系的聯(lián)系者,include會(huì)關(guān)聯(lián)其他的URLconf到本URLconf,靠include()才能夠讓Django的URL設(shè)計(jì)變得非常的靈活和簡(jiǎn)潔。include()有三個(gè)參數(shù),第一個(gè)參數(shù)不必多說(shuō),它指定了要包含的其它URLconf的路徑,關(guān)鍵是剩下的兩個(gè)參數(shù),一個(gè)是namespace, 一個(gè)是app_name,有什么用呢?其實(shí),這兩個(gè)參數(shù)再加上url()方法中的name參數(shù),共同構(gòu)成了Django中URL的命名空間,而命名空間主要是為了URL反解的,那什么是URL反解呢?我們現(xiàn)在能根據(jù)請(qǐng)求的一個(gè)URL路徑,找到對(duì)應(yīng)的view處理方法,那么反過(guò)來(lái),我們?cè)趘iew方法中,或者是template中,根據(jù)傳遞過(guò)來(lái)的參數(shù),能夠解析出對(duì)應(yīng)的URL,這就是URL反解。為什么需要URL反解呢?主要是為了不要把程序?qū)懰懒耍绻覀冊(cè)趆tml中直接把路徑寫死了,那么以后改起來(lái)就會(huì)非常的麻煩,所以常常會(huì)把這些可變的東西放到一個(gè)變量中,在程序中引用的是這個(gè)變量名,這是寫程序的一個(gè)常識(shí)吧。所以,我們能從這個(gè)“樹(shù)”中,從上到下,也得能夠從下到上。

在template中進(jìn)行反解使用的是{%url%}這個(gè)tag,在view中,進(jìn)行反解,使用的是`django.core.urlresolvers.reverse()這個(gè)方法。

好,先來(lái)看一個(gè)最簡(jiǎn)單的例子:

mydjango/urls.py:

urlpatterns = patterns('',
  url(r'model/', include('model_test.urls')),
)

model_test/urls.py:

urlpatterns = patterns('',
  url(r'^$', views.index, name='index'),
)

mydjango/urls.py是根URLconf,它包含了model_test的URLconf,modul_test中的urlpatterns中有一個(gè)命名為index的url映射對(duì)象。

如果我們想在template中得到這個(gè)view對(duì)應(yīng)的url的真實(shí)路徑,那么用template的url tag就行了:

{% url 'index' %}

這樣得到的結(jié)果就是: /model/。

同理,如果在view方法中,那么使用reverve()方法:

from django.core.urlresolvers import reverse
reverse("index")

得到的也是: /model/

在這個(gè)例子中,我們只使用到了url()方法中的name參數(shù),并沒(méi)有用到命名空間,因?yàn)檫@種簡(jiǎn)單的情況,沒(méi)有產(chǎn)生混淆,還沒(méi)有必要用到命名空間,使用命名空間的主要有以下兩種情況:

當(dāng)在一個(gè)項(xiàng)目中,有多個(gè)應(yīng)用,應(yīng)用中定義的url映射對(duì)象的name有可能有重復(fù)的,這樣當(dāng)進(jìn)行反解時(shí),Django就不能確定到底是哪個(gè)應(yīng)用了

當(dāng)在一個(gè)項(xiàng)目中,同一個(gè)應(yīng)用,被部署多個(gè)實(shí)例時(shí),這多個(gè)實(shí)例之間是共享定義的name url的,所以在進(jìn)行反解時(shí),也不能確定,到底是哪個(gè)實(shí)例

第一種情況,其實(shí)是比較好解決的,在每一個(gè)應(yīng)用的include()中,指定不同的namespace參數(shù)就可以了,如:

mydjango/urls.py:

urlpatterns = patterns('',
  url(r'model/', include('model_test.urls', namespace='model')),
)

這樣,在template中或者是reverse中,在name前需要加上namepace進(jìn)行反解:

{% 'model:index' %}
or 
reverse("model:index")

這樣就可以準(zhǔn)確的反解到model_test這個(gè)應(yīng)用中。

第二種情況,什么叫“一個(gè)應(yīng)用,被部署多個(gè)實(shí)例”呢?其實(shí)就是這種情況:

urlpatterns = patterns('',
  url(r'model1/', include('model_test.urls')),
  url(r'model2/', include('model_test.urls')),
)

不同的路徑下,引用的是相同的應(yīng)用,同一個(gè)應(yīng)用,被實(shí)例化了兩次,這種情況,怎么進(jìn)行區(qū)分呢?我能像第一種情況一樣,在include中指定不同的namespace來(lái)解決問(wèn)題嗎?答案是可行的,但是不推薦。要知道,他們引用的是同一個(gè)應(yīng)用,同一個(gè)應(yīng)用意味著什么,意味著代碼是一樣的,你在同一份代碼中,通過(guò)if/else來(lái)判斷該反解到哪個(gè)namespace中,這個(gè)做法是非常不優(yōu)雅的,嚴(yán)重違背了Django的DRY原則。

那Django通過(guò)什么辦法來(lái)解決這個(gè)問(wèn)題呢?它通過(guò)app_name + namespace + current_app的方式來(lái)解決。namespace, app_name分別為include()的第二個(gè)和第三個(gè)參數(shù),app_name指定這個(gè)應(yīng)用的名稱,namespace指定這個(gè)應(yīng)用某個(gè)實(shí)例的url的命名空間,current_app則是根據(jù)請(qǐng)求的路徑,解析出的該url的命名空間,也就是namespace,在進(jìn)行反解時(shí),動(dòng)態(tài)的將該current_app傳遞給反解的函數(shù)中,反解的函數(shù)就可以根據(jù)這個(gè)namespace,來(lái)確定應(yīng)該反解到哪個(gè)實(shí)例中了。同一個(gè)應(yīng)用的多個(gè)實(shí)例的app_name應(yīng)該是相同的,而namespace應(yīng)該是不同的??赡苡悬c(diǎn)亂了,我們?cè)賮?lái)舉個(gè)例子:

mydjango/urls.py:

urlpatterns = patterns('',
  url(r'model1/', include('model_test.urls', namespace='model_1', app_name="app")),
  url(r'model2/', include('model_test.urls', namespace='model_2', app_name="app")),
)

model_test/urls.py:

urlpatterns = patterns('',
  url(r'^$', views.index, name='index'),
)

model_test/views.py:

from django.shortcuts import render
from django.core.urlresolvers import reverse

def index(request):
  current_app = request.resolver_match.namespace
  print reverse("app:index", current_app=current_app)
  return render(request, 'model/index.html', current_app=current_app)

model_test/templates/model/index.html:

{% url 'app:index' %}

在view中,首先獲得當(dāng)前的namespace,然后通過(guò)current_app傳遞給reverse(),reverse就可以知道應(yīng)該解析到哪個(gè)實(shí)例中了。同理,在templace中,也需要將current_app傳遞過(guò)去。這樣,我們就可以動(dòng)態(tài)的反解URL了:

當(dāng)我們請(qǐng)求的路徑是/model1/時(shí),current_app就是model_1,再根據(jù)app_name,就可以準(zhǔn)確的反解出該URL為:/model1/,
如果請(qǐng)求的路徑是/model2/,那么current_app就是model_2,反解的路徑就是/model2/。

雖然有點(diǎn)復(fù)雜,但是這種情況用的比較少,google了很久,才把這種情況大概弄清楚,也許理解的有不對(duì)的地方,待以后實(shí)踐去檢驗(yàn),現(xiàn)在關(guān)鍵在于理解這種機(jī)制思想。

全文完,更多詳細(xì)的內(nèi)容,參見(jiàn)Django官方文檔:https://docs.djangoproject.com/en/1.6/topics/http/urls/

總結(jié)

以上就是本文關(guān)于Python探索之URL Dispatcher實(shí)例詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)啊參閱本站:Python探索之Metaclass初步了解、Python編程之Re模塊下的函數(shù)介紹等,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持。

相關(guān)文章

  • Python input函數(shù)使用實(shí)例解析

    Python input函數(shù)使用實(shí)例解析

    這篇文章主要介紹了Python input函數(shù)使用實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • python3 http.client/server post傳輸json問(wèn)題

    python3 http.client/server post傳輸json問(wèn)題

    這篇文章主要介紹了python3 http.client/server post傳輸json問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Python 25行代碼實(shí)現(xiàn)的RSA算法詳解

    Python 25行代碼實(shí)現(xiàn)的RSA算法詳解

    這篇文章主要介紹了Python 25行代碼實(shí)現(xiàn)的RSA算法,結(jié)合實(shí)例形式詳細(xì)分析了rsa加密算法的概念、原理、相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-04-04
  • python3.6+opencv3.4實(shí)現(xiàn)鼠標(biāo)交互查看圖片像素

    python3.6+opencv3.4實(shí)現(xiàn)鼠標(biāo)交互查看圖片像素

    這篇文章主要為大家詳細(xì)介紹了python3.6+opencv3.4實(shí)現(xiàn)鼠標(biāo)交互查看圖片像素,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 淺談Python使用pickle模塊序列化數(shù)據(jù)優(yōu)化代碼的方法

    淺談Python使用pickle模塊序列化數(shù)據(jù)優(yōu)化代碼的方法

    這篇文章主要介紹了淺談Python使用pickle模塊序列化數(shù)據(jù)優(yōu)化代碼的方法,pickle模塊可以對(duì)多種Python對(duì)象進(jìn)行序列化和反序列化,序列化稱為pickling,反序列化稱為unpickling,需要的朋友可以參考下
    2023-07-07
  • Python math庫(kù) ln(x)運(yùn)算的實(shí)現(xiàn)及原理

    Python math庫(kù) ln(x)運(yùn)算的實(shí)現(xiàn)及原理

    這篇文章主要介紹了Python math庫(kù) ln(x)運(yùn)算的實(shí)現(xiàn)及原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • pycharm2021激活碼使用教程(永久激活親測(cè)可用)

    pycharm2021激活碼使用教程(永久激活親測(cè)可用)

    pycharm2021激活碼是一個(gè)可以輕松幫助用戶免費(fèi)激活pycharm2021.1軟件的文件,雖然說(shuō)pycharm現(xiàn)在只是推出了2021.1的EAP版,但是如果你想先率先體驗(yàn)一波,那么就可以利用小編提供的這個(gè)激活碼來(lái)進(jìn)行使用啦,并這個(gè)激活碼是永久有效的
    2021-03-03
  • Python 獲取 datax 執(zhí)行結(jié)果保存到數(shù)據(jù)庫(kù)的方法

    Python 獲取 datax 執(zhí)行結(jié)果保存到數(shù)據(jù)庫(kù)的方法

    今天小編就為大家分享一篇Python 獲取 datax 執(zhí)行結(jié)果保存到數(shù)據(jù)庫(kù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • Python flask返回中文亂碼的解決方法分享

    Python flask返回中文亂碼的解決方法分享

    有時(shí)使用flask返回?cái)?shù)據(jù)會(huì)出現(xiàn)帶有中文的時(shí)候會(huì)顯示成亂碼(ascii)的情況出現(xiàn),所以本文為大家整理了一下解決的方法,需要的小伙伴可以參考一下
    2023-07-07
  • Python實(shí)現(xiàn)飛機(jī)大戰(zhàn)項(xiàng)目

    Python實(shí)現(xiàn)飛機(jī)大戰(zhàn)項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)飛機(jī)大戰(zhàn)項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評(píng)論