綜述
設計一個web應用的URLs,你需要新建一個Python模塊來進行URL設置(URLconf)。這個模塊中純Python代碼的并且是一個URL patterns(正則表達式)與Python函數(views)之間的映射匹配。
Django完成一個網絡請求的過程。
<li>通常在setting.py文件中使用ROOT_URLCONF設置app的根URL,訪問的HttpRequest對象有一個屬性是urlconf,對應的值就是ROOT_URLCONF設置的值.
<li>Django加載上文中新建的模塊,并且尋找相應urlpatterns。urlpatterns是一個包含django.conf.urls.url()實例的列表。
<li>Django從上到下搜索每一個URL pattern,在第一個能夠匹配的url()實例出停止。
<li>一旦匹配成功Django就會倒入并且調用一個函數(或者是一個class-based view)返回一個視圖。獲取試圖的參數通過以下方式傳遞
<ol>
<li>通過HttpRequest實例傳遞。
<li>url()實例的正則表達式中傳遞參數
<li>django.conf.urls.url() 關鍵字傳遞參數
</ol>
<li>如果沒有匹配或者匹配過程中出現異常,Django將拋出異常
<pre>
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
</pre>
<li>一個http:www.XXX/articles/2005/03/請求將會匹配第三個入口,Django將會調用views.month_archive(request, '2005', '03')函數
<li>/articles/2005/3/不會任何匹配,因為第三個入口中需要月份參數是兩位數。
<li>/articles/2003/將會匹配第一個模式而不是第二個。因為第一個匹配成功了,就不會繼續往下走
<li>/articles/2003不會有任何的匹配。上文中的每個pattern的結尾都必須要有一個"/"
<li>/articles/2003/03/03/ 匹配最后一個模式。并且調用views.article_detail(request, '2003', '03', '03')函數。
采用 name groups
采用正則表達式(?P<name>pattern)patter來匹配,捕獲的之作為關鍵之參數傳遞給視圖表達式。
<pre>
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
</pre>
<li>/articles/2005/03/,將會調用 views.month_archive(request, year='2005', month='03')
<li>/articles/2003/03/03/ --->views.article_detail(request, year='2003', month='03', day='03')
同時傳遞給視圖函數的總是strings
URLconf結果
URLconf把一個requested URL當成一個普通的Python string搜索。與請求的方法無關(POST、GET)
https://www.example.com/myapp/ --->匹配 myapp/
https://www.example.com/myapp/?page=3 ----->匹配 myapp/ 參數可以通過視圖函數的request對象實例相關方法回去 request.GET['page']
指定默認值
<pre>
URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
View (in blog/views.py)
def page(request, num="1"):
# Output the appropriate page of blog entries, according to num.
...
在上面的例子中,兩個URL模式指向相同的視圖-views.page-。但是第一個模式并沒有從URL中捕捉到任何東西。如果第一個模式匹配,那么page()函數將使用它的默認參數num“1”。如果第二個模式匹配,page()將使用regex捕獲的任何num值
</pre>
Including other URLconfs
include() 函數,可以把urlpatterns放到別的地方去設置
<pre>
from django.conf.urls import include, url
urlpatterns = [
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
]
把所有以community開頭的請求都交由django_website.aggregator.urls去處理
</pre>
也是一種拆分urlpatterns臃腫的辦法
<pre>
from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
url(r'^reports/$', credit_views.report),
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)),
]
例子中/credit/reports/ 將有credit_views.report()處理。 現在 url(r'^credit/', include(extra_patterns))匹配,再在extra_patterns 尋找進一步的匹配
</pre>
include()參數的獲取
<pre>
In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
]
In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.blog.index),
url(r'^archive/$', views.blog.archive),
]
diyinqianchang/blog/archive/ --->views.blog.archive(request,username='diyinqianchang')
def archive(request,username=None)
</pre>
Reverse resolution of URLs
在編寫web程序時,有時候會需要在網頁上嵌入一個連接,用于跳轉。也可以用設計好的pattern來產生匹配格式的網址。
<li>在templates中使用此url的標記
<li>在Python代碼中reverse()函數 reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
<li> get_absolute_url()函數
name 標記
<pre>
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
]
<a href="{% url 'news-year-archive' 2015%}"></a>
</pre>
reverse()
<pre>
from django.urls import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
year = 2006
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
</pre>
URL命名空間
URL 命名空間允許你反查到唯一的,即使不同的應用使用相同的URL 名稱。第三方應用始終使用帶命名空間的URL 是一個很好的實踐。
當解析一個帶命名空間的URL(例如'polls:index')時,Django 將切分名稱為多個部分,然后按下面的步驟查找:
<li>首先,Django 查找匹配的 application namespace, 在下面的例子中為'polls'。這將得到該應用實例的一個列表。
<li>如果當前應用屬性被定義,Django將查找并返回那個實例的URL解析器。當前應用屬性可在reverse() 函數中通過current_app來指定。
<li>如果沒有當前應用。Django 將查找一個默認的應用實例。默認的應用實例是[instance namespace和application namespace 一致的那個實例(在下面例子中,polls的一個叫做'polls' 的實例)
<li>如果沒有默認的應用實例,Django 將挑選該應用最后部署的實例,不管實例的名稱是什么。
<li>如果提供的命名空間與第1步中的application namespace 不匹配,Django 將嘗試直接將此命名空間作為一個 instance namespace查找。
<pre>urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
</pre>
<pre>polls/urls.py
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]
</pre>
本例中author-polls和publisher-polls都有相同連寫的主頁和詳細鏈接,被include() 在polls/urls.py
<li>如果其中一個實例是當前實例 —— 如果我們正在渲染'author-polls' 實例的detail 頁面 —— 'polls:index' 將解析成'author-polls' 實例的主頁面;例如下面兩個都將解析成"/author-polls/"。
<pre>第一和第二
reverse('polls:index', current_app=self.request.resolver_match.namespace)
{% url 'polls:index' %}
</pre>
<li>如果沒有當前實例——假如說我們在站點的其他地方渲染頁面——'polls:index'將解析到最后注冊到polls的實例。因為沒有默認的實例(實例命名空間為polls),將用注冊的polls的最后一個實例。它將是'publisher-polls',因為它是urlpatterns中最后一個聲明的.
<li>'author-polls:index' 將永遠解析到 'author-polls' 實例的主頁('publisher-polls' 類似) 沒有用什么命名空間,用name來標記