第26天,Django之include本質

weixin_34236497發表於2018-01-15

目錄

一、 URL name詳解
    向檢視傳遞額外的引數
    利用reverse函式反向生成URL
    對有引數的url設定name
二、include路由轉發
    傳遞額外的引數給include()
三、URL名稱空間
四、include()本質

一、 URL name詳解

from django.conf.urls import url
from django.contrib import admin
from calc import views as calc_views
 
 
urlpatterns = [
    url(r'^add/$', calc_views.add, name='add'),
    url(r'^add/(\d+)/(\d+)/$', calc_views.add2, name='add2'),
    url(r'^admin/', admin.site.urls),
]

url(r'^add/$', calc_views.add, name='add'), 這裡的 name='add' 是用來幹什麼的呢?

簡單說,name 可以用於在 templates, models, views ……中得到對應的網址,相當於“給網址取了個名字”,只要這個名字不變,網址變了也能通過名字獲取到。

模板中可以這樣利用name

不帶引數的:
{% url 'name' %}

帶引數的:引數可以是變數名
{% url 'name' 引數 %}

結合上面的urls.py

不帶引數:
<a href="{% url 'add' %}">新增</a>

上面模板經過渲染後的標籤是這樣的:
<a href="/add/">新增</a>


帶引數的:
<a href="{% url 'add2' 4 5 %}">link</a>

經過渲染後:
<a href="/add/4/5/">link</a>

當 urls.py 進行更改,前提是不改 name(這個引數設定好後不要輕易改),獲取的網址也會動態地跟著變,比如改成:

url(r'^new_add/(\d+)/(\d+)/$', calc_views.add2, name='add2'),

注意: add 變成了 new_add,但是後面的 name='add2'沒改,這時 {% url 'add2' 4 5 %} 就會渲染對應的網址成/new_add/4/5/

向檢視傳遞額外的引數

url()中允許你傳遞一個Python字典作為額外的關鍵字引數給檢視函式。

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

在上面的例子中,對於/blog/2005/請求,Django將呼叫views.year_archive(request, year='2005', foo='bar')。

注意:命名關鍵字引數和在字典中傳遞的額外引數要避免重名。

利用reverse函式反向生成URL

urls.py

from app01 import views as views

urlpatterns = [
    url(r'^login/',views.login),
    url(r'^index/first/',views.index,name='first'),
]

views.py

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse

def login(request):
    url = reverse('first')
    print(url)  # 列印結果:/index/first/
    return redirect(url)


def index(request):
    return HttpResponse('index/first')

對有引數的url設定name

urls.py:

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' 2012 %}">2012 Archive</a>   # 注意模版語言的用法,注意引數的傳遞方法
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

views.py檢視函式:

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

二、include路由轉發

通常,我們會在每個app裡,各自建立一個urls.py路由模組,然後從根路由出發,將app所屬的url請求,全部轉發到相應的urls.py模組中。

建立兩個app:cmdb和openstack,並分別在這兩個app目錄下建立urls.py檔案

from django.conf.urls import url,include    
    # 需要先匯入include函式
from django.contrib import admin
from app01 import views

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^cmdb/',include('cmdb.urls')),
    url(r'^openstack/',include('openstack.urls')),
]

傳遞額外的引數給include()

引數會傳遞給include指向的urlconf中的每一行,例如,下面兩種URLconf配置方式在功能上完全相同:

配置一:

# main.py
from django.conf.urls import include, url

urlpatterns = [
    url(r'^blog/', include('inner'), {'blogid': 3}),
]

# inner.py
from django.conf.urls import url
from mysite import views

urlpatterns = [
    url(r'^archive/$', views.archive),
    url(r'^about/$', views.about),
]

配置二:

# main.py
from django.conf.urls import include, url
from mysite import views

urlpatterns = [
    url(r'^blog/', include('inner')),
]

# inner.py
from django.conf.urls import url

urlpatterns = [
    url(r'^archive/$', views.archive, {'blogid': 3}),
    url(r'^about/$', views.about, {'blogid': 3}),
]

注意,只有當你確定被include的URLconf中的每個檢視都接收你傳遞給它們的額外的引數時才有意義,否則其中一個以上檢視不接收該引數都將導致錯誤異常。

三、URL名稱空間

URL名稱空間可以保證反查到唯一的URL。

urls.py

from django.conf.urls import url,include

urlpatterns = [
    url(r'^cmdb/',include('cmdb.urls',namespace='cmdb')),
    url(r'^openstack/',include('openstack.urls',namespace='openstack')),
]

cmdb/urls.py

from django.conf.urls import url
from cmdb import views

urlpatterns = [
    url(r'host/',views.host,name='host'),
]

在模板中使用

<a href="{% url 'cmdb:host' %}">跳轉</a>

在檢視中利用reverse()函式反向生成url

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse
def host(request):
    url = reverse('cmdb:host')
    print(url)      # 列印結果:/cmdb/host/
    return HttpResponse('cmdb.host')

注意:namespace與name在模板檔案和檢視函式中使用的時候要用冒號分隔,如:“cmdb:host”

四、include()本質

include()函式實際上就是返回一個元組:([], None, None)
第一個元素可以是一個列表,列表中盛放url()子路由配置;
第二個元素是app_name,可以為None;
第三個元素是namespace,需要反向生成url時,可根據需求填寫;

所以urls.py也可以這樣寫:

from django.conf.urls import url

urlpatterns = [
    url(r'^openstack/',([],None,None,),
]

直接用一個元組替代include()

如下,直接進行子路由分發:

from django.conf.urls import url,include
from cmdb import views as cviews
from app01 import views

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^index/',views.index,name='index'),
    url(r'^cmdb/',include('cmdb.urls',namespace='cmdb')),
    # url(r'^openstack/',include('openstack.urls',namespace='openstack')),
    url(r'^openstack/',([
        url(r'^host/',cviews.host,name='host'),
        url(r'^host/add/',cviews.addhost,name='addhost'),
        url(r'^host/(\d+)/change',cviews.changehost,name='changehost'),
    ],None,'openstack')),
]

以上元組中的'openstack',就相當於include()函式的namespace='openstack'

相關文章