django -- urls.py
這個模組是python單嗎,而且是一個將URL路徑和python方法進行對映的程式碼。
這個mapping關係可以根據需求,可長可短。可以涉及到其他的mappings。因為是python程式碼,所以也可以進行動態的修改。
django提供了一種將urls翻譯為其他語言的方式。
如何操作一個request請求
當用戶發起一個請求的時候,下面就是django如何通過演算法進行選擇執行哪個python方法。
1: django決定簡要使用個URLconfig模組。一般,這是一個ROOT_URLCONFI配置檔案的一個值。但是如果傳送過來的request請求有一個urlconfig屬性。(通過中間軟體設定),那麼這個值在這裡將會用到。
2:django載入python模組,並且尋找url規則進行匹配。這個url規則將會是一個path或者re_path的集合。
3:django通過各種的url規則,將會在第一個匹配到的規則那裡停止下來。
4:一單匹配了其中一個url規則,django將會倒入並且呼叫對應的view。python的方法。view可以獲取下面的資料。
1:一個httprequest物件
2:如果url規則返回的是一個沒有命名的組,那麼匹配到的將會是一個位置引數。
3:關鍵字引數就是re表示式中的命名的組,
4:
5:如果沒有url規則匹配。或者說在這個過程中丟擲了異常。django將會丟擲異常。
from django.urls import path from . import views urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
需要注意的是:
1:通過尖括號進行捕獲值。
2:捕獲的值可以可選的進行轉換型別。比如上面的將year轉化成為int。如果沒有,除了斜槓之外的所有字串都可以匹配。
3:沒有必要去新增前置斜槓,因為每一個url都有。比如說 articales就不需要 /articals.根據上面的例子,下面的呼叫。
/articles/2005/03/
匹配第3個views.month_archive(request, year=2005, month=3)
.
/articles/2003/ 匹配第一個 views.special_case_2003(request)
/articles/2003 不匹配
/articles/2003/03/building-a-django-site/ 最後一個views.article_detail(request, year=2003, month=3, slug="building-a-django-site")
.
強轉 int
str 除了斜槓以外的所有
int 0或者其他正整數,不包括負數。
slug 負數以及-_字母
path 匹配所有的非空字元包括/
新增強轉規則。
為了更復雜匹配的需求。你自定義conventer類。標準如下:
1: 一個regex屬性,而且是string。
2:一個to_python(self,value)方法,這個返回將匹配到的string轉化為對應型別的值。這個值將會傳入view方法中。如果不能轉換成為給定的值,那麼將會丟擲異常。
3:一個to_url(sel,value)方法,將會將轉化後的資料轉化成為一個字串,這個將在URL中使用。class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value
通過方法register_converter進行註冊。
from django.urls import path, register_converter from . import converters, views register_converter(converters.FourDigitYearConverter, 'yyyy') urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<yyyy:year>/', views.year_archive), ... ]
通過正則表示式。
如果path和converter語法都不能滿足你定義URL規則,那麼你可以通過正則進行獲取。如果要這樣就需要使用re_path,而不是path.
在python正則表示式中。為了獲取一個命名的組,語法如下(?P<name>pattern)。name就是組的名字,pattern就是規則。from django.urls import path, re_path from . import views urlpatterns = [ path('articles/2003/', views.special_case_2003), re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail), ]
這個例子和上面的例子中工作的效果完全一模一樣。除了。
1:具體的URL將要匹配得更嚴格。比如,10000年將不會匹配,因為year整型值被認定為四位數。
2:每一個數據都會被當做整型進行匹配,和匹配的順序沒有關係。當從使用path到使用gre_path,我們需要關切view引數的資料型別可能會發生變化,所以你有必要去修改你的view。反之亦然。
我們同樣可以使用未命名的引數,雖然這樣跟簡單。但是不建議這麼做。除非明確只有一個數據的時候。而且這種方法更容易導致錯誤。還有命名和未命名的組不能混合使用,因為,兩者混合,未命名的將會被忽略掉。
而且同樣不建議使用巢狀組,但是可以通過(?:pattern)進行避免。
URLconf搜尋用來幹啥的呢?
這個僅僅用來搜尋url,把url當成string型別來使用。這個不包括get,post引數。或者說是域名。
比如說對於 https://www.example.com/myapp/,URLconf僅僅查詢 myapp/.
同樣https://www.example.com/myapp/?page=3 ,也僅僅查詢myapp,而忽略引數。urlconf不會檢視requets的方法,也就是說,不管你怎麼樣,都要經過我這兒。
為view設定預設值。
一個很方便的使用方式就是為view的引數設定哦認知。比如說。
# URLconf from django.urls import path from . import views urlpatterns = [ path('blog/', views.page), path('blog/page<int:num>/', views.page), ] # View (in blog/views.py) def page(request, num=1): # Output the appropriate page of blog entries, according to num. ...
所有的在urlpatterns中的規則都只會在第一次使用連結的時候編譯。也就是匹配,逐一匹配url。
urlpattern物件必須是一個由path或者re_path組成的集合。
使用其他的urlpattern
z在任何時候,你的urlpatterns都可以包含其他urlconfig模組的內容。這個root連線必須是前後關係,不能是子父,只能是父子關係的那種。這是為了滿足真正的需要,但是實際上可以 的。
比如下面的這個例子是Django本身對其他的引用。包含了其他的URLconf模組。from django.urls import include, path urlpatterns = [ # ... snip ... path('community/', include('aggregator.urls')), path('contact/', include('contact.urls')), # ... snip ... ]
無論什麼時候Django遇到了include。它都會擷取掉匹配的字串,然後將剩下的交給include裡面的URLconf。去做更深遠的處理。
另一種可能是通過path包含一個額外的URLpattern。比如說下面的例子。
from django.urls import include, path from apps.main import views as main_views from credit import views as credit_views extra_patterns = [ path('reports/', credit_views.report), path('reports/<int:id>/', credit_views.report), path('charge/', credit_views.charge), ] urlpatterns = [ path('', main_views.homepage), path('help/', include('apps.help.urls')), path('credit/', include(extra_patterns)), ]
這個例子就是在path的第二個引數include中包含了前面的include。然後再urlpatterns的第一個就是呼叫了其他view裡面的方法。上面的credit/reports將會被傳遞給 credit_views.report方法。
當一個prefix被多次重複的使用的時候,我們就可以通過刪除榮譽的方式進行使用。比如下面的這些。
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ]
也就是有一些網站在中間插入了檔案的年月日等資訊作為資料項。後面的也都統一。
我們可以通過包含的方式進行簡化。
from django.urls import include, path from . import views urlpatterns = [ path('<page_slug>-<page_id>/', include([ path('history/', views.history), path('edit/', views.edit), path('discuss/', views.discuss), path('permissions/', views.permissions), ])), ]
確實有點東西呀。
獲取引數。
一種通過include urlconf的方式進行包含的是可以獲取所有捕獲到的資料的,所以下面的這些列子是合法的。
# In settings/urls/main.py from django.urls import include, path urlpatterns = [ path('<username>/blog/', include('foo.urls.blog')), ]
# In foo/urls/blog.py from django.urls import path from . import views urlpatterns = [ path('', views.blog.index), path('archive/', views.blog.archive), ]
也就是說,main.py中捕獲的username將會傳遞給foo.urls.blog中。
可以通過dict的方式傳遞其他額外的資料。
from django.urls import path from . import views urlpatterns = [ path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}), ]
/blog/2005/ views.year_archive(request, year=2005, foo='bar')
如果獲取到和我們傳入的衝突了,那麼將會使用字典裡面的而不是url中捕獲的。
給include傳遞額外的資料。
# main.py from django.urls import include, path urlpatterns = [ path('blog/', include('inner'), {'blog_id': 3}), ] # inner.py from django.urls import path from mysite import views urlpatterns = [ path('archive/', views.archive), path('about/', views.about), ]
需要注意的是通過include包含其他conf,所有的path都將會收到傳遞過去的資料。也不管這些view是否真的接受這些引數。也正是這個原因,你最好確認一下是不是所有的urlconf都接受這個額外的資料。
# main.py from django.urls import include, path from mysite import views urlpatterns = [ path('blog/', include('inner')), ] # inner.py from django.urls import path urlpatterns = [ path('archive/', views.archive, {'blog_id': 3}), path('about/', views.about, {'blog_id': 3}), ]
和上面的類似。
path的命名
給自己當前的URL命名,可以讓你在其他地方很明顯的呼叫。尤其是在模版裡面。這個強大的特性可以讓你在一個檔案裡面給所有的全域性URL賦值。
path專講
path是一個方法,返回一個元素。元素型別為 <class 'django.urls.resolvers.URLResolver'>
path的原型path
(route, view, kwargs=None, name=None)¶
from django.urls import include, path
urlpatterns = [
path('index/', views.index, name='main-view'),
path('bio/<username>/', views.bio, name='bio'),
path('articles/<slug:title>/', views.article, name='article-detail'),
path('articles/<slug:title>/<int:section>/', views.section, name='article-section'),
path('weblog/', include('blog.urls')),
...
]
首先route引數應該是一個string型別或者是一個gettext_lazy()方法,這裡麵包含了URL匹配規則。
這個string裡面可能會有尖括號,會將捕獲到的資料傳遞到view中。而且尖括號中可以有型別轉換。這樣也就改變了傳送過去的型別。
view引數一個view的方法或者是as_view,也可以是一個 django.urls.include()方法。
kwargs 引數可以傳遞任意的引數過去。必須是dict型別。
name 普通是順序匹配,這樣可以自由匹配。而且過載的時候更加有效。link
url()是re_path的一個別名。