URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行。html
urlpatterns = [ url(正則表達式, views視圖函數,參數,別名), ]
參數說明:python
view:
當正則表達式匹配到某個條目時,自動將封裝的HttpRequest對象做爲第一個參數,正則表達式「捕獲」到的值做爲第二個參數,傳遞給該條目指定的視圖。
若是是簡單捕獲,那麼捕獲值將做爲一個位置參數進行傳遞,若是是命名捕獲,那麼將做爲關鍵字參數進行傳遞。
kwargs:
任意數量的關鍵字參數能夠做爲一個字典傳遞給目標視圖。
name:
對你的URL進行命名,可讓你可以在Django的任意處,尤爲是模板內顯式地引用它。至關於給URL取了個全局變量名,你只須要修改這個全局變量的值,
在整個Django中引用它的地方也將一樣得到改變。這是極爲古老、樸素和有用的設計思想,並且這種思想無處不在。
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), path('login/', views.login), # 路由配置: 路徑--------->視圖函數 # 正則匹配:r'^articles/2003/$' 以articles/2003/開頭且以articles/2003/結尾 re_path(r'^articles/2003/$', views.special_case_2003), # special_case_2003(request) # 正則匹配四位的任意數字,多對一 re_path(r'^articles/(/[0-9]{4})/$', views.year_archive), # year_archive(request,1999) # 正則匹配一個四位的數字做爲年,還要匹配一個2位的數字做爲月 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), # month_archive(request,2009,12) # 改寫爲有名分組 re_path(r'^articles/(?P<y>[0-9]{4})/(?P<m>[0-9]{2})/$', views.month_archive) # month_archive(request,y=2009,m=12) # ([0-9]+):匹配前面的數字一次或無限次做爲詳情 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail)
]
注意:正則表達式
若要從URL中捕獲一個值,值須要在它周圍放置一對圓括號。django
不須要添加一個前導的反斜槓,由於每一個URL都有。例如,應該是^articles而不是^/articles。瀏覽器
每一個正則表達式前面的'r'是可選的可是建議加上。它告訴python這個字符串是「原始的」—— 字符串中任何字符都不該該轉義bash
from django.shortcuts import render,HttpResponse def timer(request): import time ctime = time.strftime('%Y-%m-%d %H:%M:%S') # 2018-06-30 05:48:11 """ render方法: 一、幫忙找到timer.html取出裏面的數據; 二、按照固定的語法({})把變量嵌套到html文件中 """ return render(request, 'timer.html', {"date":ctime}) # 使用render方法,返回一個頁面 def special_case_2003(request): return HttpResponse("special_case_2003") # HttpResponse:響應對象 def year_archive(request,year): return HttpResponse(year) def month_archive(request,y,m): return HttpResponse(y+"-"+m)
''' 一些請求的例子: /articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數views.month_archive(request, '2005', '03')。 /articles/2005/3/ 不匹配任何URL 模式,由於列表中的第三個模式要求月份應該是兩個數字。 /articles/2003/ 將匹配列表中的第一個模式不是第二個,由於模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的狀況來探測匹配的次序。 /articles/2003 不匹配任何一個模式,由於每一個模式要求URL 以一個反斜線結尾。 /articles/2003/03/03/ 將匹配最後一個模式。Django 將調用函數views.article_detail(request, '2003', '03', '03')。 '''
APPEND_SLASH=True
上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。服務器
在Python 正則表達式中,命名正則表達式組的語法是(?Ppattern),其中name 是組的名稱,pattern 是要匹配的模式。 下面是以上URLconf 使用命名組的重寫:app
from django.urls import path,re_path from app01 import views urlpatterns = [ re_path(r'^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<day>[0-9]{2})/$', views.article_detail), ]
這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。例如視圖函數month_archive:函數
def month_archive(request,year,month): return HttpResponse(year+"-"+month)
url訪問調用效果以下:工具
/articles/2005/03/ 請求將調用views.month_archive(request, year='2005', month='03')函數,而不是views.month_archive(request, '2005', '03')。 /articles/2003/03/03/ 請求將調用函數views.article_detail(request, year='2003', month='03', day='03')
在實際應用中,這意味你的URLconf 會更加明晰且不容易產生參數順序問題的錯誤 —— 你能夠在你的視圖函數定義中從新安排參數的順序。固然,這些好處是以簡潔爲代價;有些開發人員認爲命名組語法醜陋而繁瑣。
爲了實現路由解耦,建立/first_pro/app01/urls.py文件。將/first_pro/first_pro/urls.py中關於app01的路由配置註釋。
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), path('login/', views.login), #分發: # re_path(r"app01/", include("app01.urls")) # 改寫以下:不用app01 re_path(r"^", include("app01.urls")) ]
1)分發配置爲re_path(r"app01/", include("app01.urls"))時:訪問頁面須要按照以下規則:
2)分發配置爲re_path(r"^", include("app01.urls"))時:訪問頁面不須要添加app01:
1)include() 的正則表達式並不包含一個 $ (字符串結尾匹配符),可是包含了一個斜杆/;
2)每當Django遇到 include() 時,它將截斷匹配的URL,並把剩餘的字符串發往包含的URLconf做進一步處理。
# -*- coding:utf-8 -*- __author__ = 'Qiushi Huang' from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ # 路由配置: 路徑--------->視圖函數 # 正則匹配:r'^articles/2003/$' 以articles/2003/開頭且以articles/2003/結尾 re_path(r'^articles/2003/$', views.special_case_2003), # special_case_2003(request) # 正則匹配四位的任意數字,多對一 re_path(r'^articles/([0-9]{4})/$', views.year_archive), # year_archive(request,1999) # 正則匹配一個四位的數字做爲年,還要匹配一個2位的數字做爲月 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), # month_archive(request,2009,12) # 改寫爲有名分組 re_path(r'^articles/(?P<y>[0-9]{4})/(?P<m>[0-9]{2})/$', views.month_archive) # month_archive(request,y=2009,m=12) # ([0-9]+):匹配前面的數字一次或無限次做爲詳情 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail) ]
一、在/first_pro/first_pro/urls.py中,編寫路由配置login:
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), path('login/', views.login) ]
二、修改/first_pro/app01/views.py文件,配置login視圖函數
from django.shortcuts import render,HttpResponse def login(request): print(request.method) # GET或POST # get請求來的話拿到頁面,post請求來的話作校驗 if request.method == 'GET': return render(request, "login.html") # post請求 else: print(request.POST) # <QueryDict: {'user': ['yuan'], 'pwd': ['123']}> user = request.POST.get("user") pwd = request.POST.get("pwd") if user=="yuan" and pwd=="123": return HttpResponse("登陸成功") # 返回字符串 else: return HttpResponse("用戶名或密碼錯誤!")
取請求的方式:request.method。
獲得GET請求的時候,經過render方法拿到頁面;獲得POST請求的時候,因爲request.POST獲得一個字典,經過get()方法拿到鍵值。
三、在/first_pro/templates/中,建立login.html模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--在不指名action的狀況下,默認使用當前頁面的ip地址和端口(同源)--> <form action="http://127.0.0.1:8000/login/" method="post"> 用戶名 <input type="text" name="user"> 密碼 <input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
action表明的是一個路徑。因爲同源的緣由,能夠寫爲action="http://127.0.0.1:8000/login/",也能夠寫爲action="/login/"。
因爲提交的是login函數,在urls.py控制器中查找到對應的path('login/', views.login)。找到對應的視圖函數來進行處理。
四、在瀏覽器登陸,輸入正確用戶名和密碼後,執行效果:
在使用Django 項目時,一個常見的需求是得到URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。
獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供一個辦法是讓URL 映射是URL 設計惟一的地方。你填充你的URLconf,而後能夠雙向使用它:
第一種方式是咱們在前面一直討論的用法。第二種方式叫作反向解析URL、反向URL 匹配、反向URL 查詢或者簡單的URL 反查。
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:
django.core.urlresolvers.reverse()
函數。get_absolute_url()
方法。(1)修改配置/first_pro/first_pro/urls.py,設置別名
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), # path('login/', views.login), path('login.html', views.login, name='Log'), ]
(2)修改模板first_pro/templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--在不指名action的狀況下,默認使用當前頁面的ip地址和端口(同源)--> <!--<form action="http://127.0.0.1:8000/login/" method="post">--> <form action="{% url 'Log' %}" method="post"> 用戶名 <input type="text" name="user"> 密碼 <input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
注意form表單的修改。
(3)重新路由地址訪問
注意:
1)模板中的<form action="{% url 'Log' %}" method="post">,在頁面渲染
時改成了<form action="/login/html" method="post">。django在執行return render(request,"login.html")時,並非直接返回的login.html頁面,而是通過了處理(主要是渲染模板語法)。
2)模板語法有兩種:一種是"{{ }}";一種是"{% %}"。在遇到這兩種狀況時,會進行相應的語法渲染,將渲染的結果交給頁面瀏覽器。
django.core.urlresolvers.reverse()
函數實現反向解析(1)在/first_pro/app01/urls.py中給視圖函數路由配置別名:
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ # 路由配置: 路徑--------->視圖函數 # 正則匹配:r'^articles/2003/$' 以articles/2003/開頭且以articles/2003/結尾 re_path(r'^articles/2003/$', views.special_case_2003, name="s_c_2003"), # special_case_2003(request) # 正則匹配四位的任意數字,多對一 re_path(r'^articles/([0-9]{4})/$', views.year_archive, name="y_a"), # year_archive(request,1999) # 正則匹配一個四位的數字做爲年,還要匹配一個2位的數字做爲月 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), # month_archive(request,2009,12) # 改寫爲有名分組 re_path(r'^articles/(?P<y>[0-9]{4})/(?P<m>[0-9]{2})/$', views.month_archive) # month_archive(request,y=2009,m=12) # ([0-9]+):匹配前面的數字一次或無限次做爲詳情 # re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail) ]
(2)修改/first_pro/first_pro/urls.py配置(爲了修改路徑區分更大)
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), # path('login/', views.login), path('login.html/', views.login, name='Log'), #分發: # re_path(r"app01/", include("app01.urls")) # 改寫以下:不用app01 # re_path(r"^", include("app01.urls")) re_path(r"^app01/", include("app01.urls")) ]
(3)在/first_pro/app01/views.py中導入反向解析
from django.shortcuts import render,HttpResponse # Create your views here. # 反向解析函數 from django.urls import reverse def timer(request): import time ctime = time.strftime('%Y-%m-%d %H:%M:%S') # 2018-06-30 05:48:11 url = reverse("s_c_2003") url = reverse("y_a", args=(4009,)) # '^articles/([0-9]{4})/$' print(url) # /app01/articles/4009/ """ render方法: 一、幫忙找到timer.html取出裏面的數據; 二、按照固定的語法({})把變量嵌套到html文件中 """ return render(request, 'timer.html', {"date":ctime}) # 使用render方法,返回一個頁面
(4)在瀏覽器訪問http://127.0.0.1:8000/timer/,在程序控制臺輸出:
/app01/articles/4009/,能夠發現反向解析放在任意視圖中都可以生效。
命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。
因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回。
咱們在開發項目時,會常用name屬性反解出URL,當不當心在不一樣的app的urls中定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間。
1)建立app02應用
$ python3 manage.py startapp app02
2)文件配置修改
/first_pro/first_pro/urls.py:
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), #分發: re_path(r"^app01/", include("app01.urls")), re_path(r"^app02/", include("app02.urls")), ]
/first_pro/app01/urls.py:
urlpatterns = [ # 路由配置: 路徑--------->視圖函數 # re_path("index/", views.index) re_path("index/", views.index, name="index") ]
/first_pro/app02/urls.py:
urlpatterns = [ # 路由配置: 路徑--------->視圖函數 # re_path("index/", views.index) re_path("index/", views.index, name= "index") # 別名重複 ]
/first_pro/app01/views.py:
# 反向解析函數 from django.urls import reverse def index(request): # 反向解析 return HttpResponse(reverse("index"))
/first_pro/app02/views.py:
# 反向解析函數 from django.urls import reverse def index(request): # 反向解析 return HttpResponse(reverse("index"))
3)在頁面上訪問這兩個應用地址
能夠看到兩個都解析爲/app02/index/,能夠看出在不一樣app中出現兩個別名重複,致使了URL反解錯誤。
1)配置命名空間
/first_pro/first_pro/urls.py:
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('timer/', views.timer), #分發: re_path(r"^app01/", include(("app01.urls","app01"))), # 換爲一個元組 re_path(r"^app02/", include(("app02.urls","app02"))), ]
注意:這裏include裏面包含的是一個元組
/first_pro/app01/views.py:
from django.urls import reverse def index(request): # 反向解析 return HttpResponse(reverse("app01:index"))
/first_pro/app02/views.py:
from django.urls import reverse def index(request): # 反向解析 return HttpResponse(reverse("app02:index"))
2)在頁面上訪問測試
能夠看到引入了命名空間後,URL反解正常。
思考狀況以下:
urlpatterns = [ re_path('articles/(?P<year>[0-9]{4})/', year_archive), re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view), re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view), re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view), ]
存在兩個問題:
第一個問題,函數 year_archive
中year參數是字符串類型的,所以須要先轉化爲整數類型的變量值,固然year=int(year)
不會有諸如如TypeError或者ValueError的異常。那麼有沒有一種方法,在url中,使得這一轉化步驟能夠由Django自動完成?
第二個問題,三個路由中article_id都是一樣的正則表達式,可是你須要寫三遍,當以後article_id規則改變後,須要同時修改三處代碼,那麼有沒有一種方法,只需修改一處便可?
在Django2.0中,可使用 path
解決以上的兩個問題。
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>/', views.article_detail), ]
基本規則:
<>
)從url中捕獲值。至關於有名分組,括號內的int是path內置的轉換器<int:name>
捕獲一個整數變量。若果沒有轉化器,將匹配任何字符串,固然也包括了 /
字符。對first_pro進行修改:
/first_pro/first_pro/urls.py:
from django.contrib import admin from django.urls import path,re_path, include from app01 import views urlpatterns = [ path("articles/<int:year>/",views.path_year) # path_year(request,2010) ]
/first_pro/app01/views.py:
from django.shortcuts import render,HttpResponse # Create your views here. def month_archive(request,y,m): print(m) # 11 print(type(m)) # <class 'str'> print(y) # 2010 print(type(y)) # <class 'str'> return HttpResponse(y+"-"+m) def path_year(request, year): print(year) # 2010 print(type(year)) # <class 'int'> return HttpResponse("path year")
運行效果:
同時控制檯輸出:2010和<class 'int'>,說明使用<int:year>捕獲的是一個整數變量。
如下是根據 2.0官方文檔 而整理的示例分析表:
文檔原文是Path converters,暫且翻譯爲轉化器。
Django默認支持如下5個轉化器:
對於一些複雜或者複用的須要,能夠定義本身的轉化器。轉化器是一個類或接口,它的要求有三點:
(1)建立/first_pro/app01/url_convert.py文件
class MonConvert: # regex 類屬性,字符串類型。所以不能隨便取其餘名字 regex = "[0-9]{2}" # 兩位的數字 # to_python(self, value)方法,value是由類屬性regex所匹配到的字符串,返回具體的Python變量值 def to_python(self, value): return int(value) # to_url(self, value) 方法,value是一個具體的Python變量值,返回其字符串,一般用於url反向引用 def to_url(self, value): return '%04d' % value
(2)註冊定義的url轉換器:/first_pro/first_pro/urls.py
from django.contrib import admin from django.urls import path,re_path, include, register_converter # 注意register_converter模塊引入 from app01.url_convert import MonConvert # 引入建立的轉換器 # 註冊定義的url轉換器 register_converter(MonConvert, "mm") from app01 import views urlpatterns = [ path("articles/<mm:month>", views.path_month) ]
(3)自定義轉化器/first_pro/app01/urls.py
from django.shortcuts import render,HttpResponse # 自定義轉化器 def path_month(request, month): print(month, type(month)) return HttpResponse("path month....")
(4)訪問驗證
程序控制臺輸出:12 <class 'int'>,能夠看到month被轉化爲了數字類型。