最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python探索之URL Dispatcher實例詳解

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

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

有了這個base,我們先拋出幾個問題,提前思考一下:

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

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

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

好,先來看一個簡單的例子:

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')),
)

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

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

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()

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

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

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

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

好,糾結(jié)了一大堆,還是來解析一下我們上面提到的例子,假如我們有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)我們訪問”articles/2014/”這個路徑的時候,解析的過程如下:

>>> 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)我們訪問”articles/2014/11”這個路徑時,解析的過程如下:

>>> 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'}

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

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

patterns()

接下來,我們來看patterns()方法,這個其實比較簡單,它就是返回一個由url()方法構(gòu)造的URL映射對象組成的列表。它有一個必填參數(shù)是prefix,這個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這個變量,這個變量是不能隨便定義的,必須是約定好的,默認(rèn)django會去URLconf中查找這個變量,也許你可以在某個地方設(shè)定一個參數(shù),來換個約定,改變一下這個變量名。

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

include()

我們來說include(),這其實是個難點,關(guān)鍵在于URL反解那里,Django的文檔也沒有說清楚,而且關(guān)系也比較亂,所以,必須得實際的測試一下,才會明白。

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

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

好,先來看一個最簡單的例子:

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中有一個命名為index的url映射對象。

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

{% url 'index' %}

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

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

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

得到的也是: /model/

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

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

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

第一種情況,其實是比較好解決的,在每一個應(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這個應(yīng)用中。

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

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

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

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

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,然后通過current_app傳遞給reverse(),reverse就可以知道應(yīng)該解析到哪個實例中了。同理,在templace中,也需要將current_app傳遞過去。這樣,我們就可以動態(tài)的反解URL了:

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

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

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

總結(jié)

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

相關(guān)文章

  • 使用Pytorch+PyG實現(xiàn)MLP的詳細(xì)過程

    使用Pytorch+PyG實現(xiàn)MLP的詳細(xì)過程

    圖神經(jīng)網(wǎng)絡(luò)是最近 AI 領(lǐng)域最熱門的方向之一,下面這篇文章主要給大家介紹了關(guān)于使用Pytorch+PyG實現(xiàn)MLP的詳細(xì)過程,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • 舉例講解Python程序與系統(tǒng)shell交互的方式

    舉例講解Python程序與系統(tǒng)shell交互的方式

    這篇文章主要介紹了Python程序與系統(tǒng)shell交互的方式,舉了一個非常簡單的hello world的例子,需要的朋友可以參考下
    2015-04-04
  • python如何正確的操作字符串

    python如何正確的操作字符串

    Python是一種知道如何不妨礙你編寫程序的編程語言。它易于學(xué)習(xí),功能強(qiáng)大,足以構(gòu)建Web應(yīng)用程序并自動化無聊的東西。本文是對常用字符串操作進(jìn)行了詳細(xì)的總結(jié)分析,希望對您有所幫助。
    2021-06-06
  • Python中的文件和目錄操作實現(xiàn)代碼

    Python中的文件和目錄操作實現(xiàn)代碼

    對于文件和目錄的處理,雖然可以通過操作系統(tǒng)命令來完成,但是Python語言為了便于開發(fā)人員以編程的方式處理相關(guān)工作,提供了許多處理文件和目錄的內(nèi)置函數(shù)。重要的是,這些函數(shù)無論是在Unix、Windows還是Macintosh平臺上,它們的使用方式是完全一致的。
    2011-03-03
  • python爬蟲-模擬微博登錄功能

    python爬蟲-模擬微博登錄功能

    這篇文章主要介紹了python爬蟲-模擬微博登錄功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • 如何使用pytorch實現(xiàn)LocallyConnected1D

    如何使用pytorch實現(xiàn)LocallyConnected1D

    由于LocallyConnected1D是Keras中的函數(shù),為了用pytorch實現(xiàn)LocallyConnected1D并在960×33的數(shù)據(jù)集上進(jìn)行訓(xùn)練和驗證,本文分步驟給大家介紹如何使用pytorch實現(xiàn)LocallyConnected1D,感興趣的朋友一起看看吧
    2023-09-09
  • Python+wxauto實現(xiàn)微信自動化操作

    Python+wxauto實現(xiàn)微信自動化操作

    在眾多自動化工具中,Python的wxauto庫以其強(qiáng)大的功能和簡單易用的特點,為我們打開了微信自動化操作的大門,下面我們就來看看它的具體操作吧
    2025-02-02
  • Python程序打包成可執(zhí)行文件exe詳解流程

    Python程序打包成可執(zhí)行文件exe詳解流程

    你是否也有希望過寫一些自己所需要的工具程序來使用,可有不想或者沒時間精力學(xué)別的語言,本篇文章教你如何將用python語言寫的程序打包成可執(zhí)行的exe文件
    2021-11-11
  • python之語句mode = 'test' if y is None else 'train'問題

    python之語句mode = 'test' if y&nb

    這篇文章主要介紹了python之語句mode = 'test' if y is None else 'train'問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 使用python求解迷宮問題的三種實現(xiàn)方法

    使用python求解迷宮問題的三種實現(xiàn)方法

    關(guān)于迷宮問題,常見會問能不能到達(dá)某點,以及打印到達(dá)的最短路徑,下面這篇文章主要給大家介紹了關(guān)于如何使用python求解迷宮問題的三種實現(xiàn)方法,需要的朋友可以參考下
    2022-03-03

最新評論

七台河市| 湟中县| 三都| 从化市| 阳东县| 玛沁县| 桃江县| 宁德市| 东乡县| 栾川县| 新蔡县| 始兴县| 广州市| 喀喇沁旗| 繁峙县| 鞍山市| 南宫市| 奉新县| 吉首市| 朝阳市| 赣州市| 广西| 台州市| 洛川县| 大洼县| 息烽县| 苏尼特右旗| 晋宁县| 津南区| 英山县| 西充县| 陆川县| 曲松县| 岑溪市| 项城市| 理塘县| 兴山县| 泰宁县| 同德县| 六枝特区| 育儿|