1. 程式人生 > >Django框架全面講解 -- Django 路由系統

Django框架全面講解 -- Django 路由系統

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要為該URL模式呼叫的檢視函式之間的對映表;你就是以這種方式告訴Django,對於這個URL呼叫這段程式碼,對於那個URL呼叫那段程式碼。URL的載入是從配置檔案中開始。

引數說明:
一個正則表示式字串
一個可呼叫物件,通常為一個檢視函式或一個指定檢視函式路徑的字串
可選的要傳遞給檢視函式的預設引數(字典形式)
一個可選的name引數
1. 示例

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

說明:
要捕獲從URL中的值,用括號括起來,會當引數傳入 views 檢視。
沒有必要新增一個斜線,因為每個URL都有。例如,它^articles不是^/articles。
在’r’前面的每個正則表示式字串中是可選的,但建議。它告訴Python字串是“原始” -沒有什麼字串中應該進行轉義。
請求示例:
一個請求 /articles/2005/03/ 會匹配上面列表中的第三條. Django 會呼叫函式 views.month_archive(request, ‘2005’, ‘03’).
/articles/2005/3/ 不會匹配上面列表中的任何條目, 因為第三條的月份需要二位數字.
/articles/2003/ 會匹配上第一條而不是第二條,因為匹配是按照從上到下順序而進行的, Django 會呼叫函式 views.special_case_2003(request)
/articles/2003 不會匹配上面列表中的任何條目, 因為每個URL應該以 / 結尾.
/articles/2003/03/03/ 會匹配上最後一條. Django 會呼叫函式 views.article_detail(request, ‘2003’, ‘03’, ‘03’).
2. 命名組(Named groups)
在上面的簡單例子中,並沒有使用正則表示式分組,在更高階的用法中,很有可能使用正則分組來匹配URL並且將分組值通過引數傳遞給view函式。
在Python的正則表示式中,分組的語法是 (?Ppattern), name表示分組名,pattern表示一些匹配正則.
這裡是一個簡單的小例子:

# 正則知識
import re

ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo')

print(ret.group())
print(ret.group('id'))
print(ret.group('name'))
-------------------------------------
123/ooo
123
ooo
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), ]

For example:

A request to /articles/2005/03/ 會呼叫函式 views.month_archive(request, year='2005',month='03'), 而不是 views.month_archive(request, '2005', '03').
A request to /articles/2003/03/03/ 會呼叫函式 views.article_detail(request, year='2003',month='03', day='03').

常見寫法例項:

3. 二級路由(Including)
那如果對映 url 太多怎麼辦,全寫一個在 urlpatterns 顯得繁瑣,so 二級路由應用而生

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

在上面這個例子中,如果請求url為 /credit/reports/ 則會呼叫函式 credit_views.report().
使用二級路由也可以減少程式碼冗餘,使程式碼更加簡潔易懂。

# 原始版本
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),
]


# 改進版本
from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
        url(r'^history/$', views.history),
        url(r'^edit/$', views.edit),
        url(r'^discuss/$', views.discuss),
        url(r'^permissions/$', views.permissions),
    ])),
]

4.新增額外的引數
URLconfs 有一個鉤子可以讓你加入一些額外的引數到view函式中.

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 將會呼叫函式l views.year_archive(request, year=’2017’,foo=’bar’).
需要注意的是,當你加上引數時,對應函式views.year_archive必須加上一個引數,引數名也必須命名為 foo,如下:

def year_archive(request, foo):
    print(foo)
    return render(request, 'index.html')

5.別名的使用

url(r'^index',views.index,name='bieming')

url中還支援name引數的配置,如果配置了name屬性,在模板的檔案中就可以使用name值來代替相應的url值.我們來看一個例子:

urlpatterns = [
    url(r'^index',views.index,name='bieming'),
    url(r'^admin/', admin.site.urls),
    # 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),

]
###################
def index(req):
    if req.method=='POST':
        username=req.POST.get('username')
        password=req.POST.get('password')
        if username=='alex' and password=='123':
            return HttpResponse("登陸成功")
    return render(req,'index.html')
#####################
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#     <form action="/index/" method="post">#}
{#     這裡只要使用bieming即可代替/index #}
     <form action="{% url 'bieming' %}" method="post">
         使用者名稱:<input type="text" name="username">
         密碼:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>
#######################

6.指定view的預設配置

# 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()將使用任何 num 值由正則表示式捕獲。