Django之url

Django 如何處理一個(gè)請(qǐng)求

URL解釋:

url的匹配規(guī)則:

  • 普通用法
#1.普通用法,無(wú)參數(shù)情況,配置URL及其視圖如下:
from django.conf.urls import url,include
from TestApp import views
urlpatterns = [
    url('^test/2018/$',views.TestOne.as_view())
]
#views.py
# -*- coding: utf-8 -*-
from django.views import View
from django.http import HttpResponse
class TestOne(View):
    def get(self,request):
        return HttpResponse('TestOne:普通url的寫法')

輸入地址:http://127.0.0.1:8000/test/2018/

image.png

  • 正則url寫法
#urls.py寫法:
from django.conf.urls import url,include
from TestApp import views
urlpatterns = [
    url('^test/[0-9]{4}/$',views.TestTwo.as_view())
]
#views.py寫法:
# -*- coding: utf-8 -*-
from django.views import View
from django.http import HttpResponse
class TestTwo(View):
    def get(self,request):
        return HttpResponse('TestTwo:正則url寫法')

輸入地址:http://127.0.0.1:8000/test/2017

image.png

#2.傳遞參數(shù)情況,URL中通過(guò)正則指定參數(shù):
url('^test/([0-9]{4})/$',views.TestThree.as_view())
class TestThree(View):
    def get(self,request,year):
        return HttpResponse('TestThree:帶單個(gè)非命名寫法')


url('^test/([0-9]{4})/([0-9]{2})/([0-9]{2})/$',views.TestFour.as_view())

class TestFour(View):
    def get(self,request,year,month,day):
        return HttpResponse('TestFour:帶多個(gè)非命名寫法')

#因?yàn)楫?dāng)加上圓括號(hào)的時(shí)候,django就能從URL中捕獲這一個(gè)值并傳遞給相對(duì)應(yīng)的views函數(shù),當(dāng)然使用的是位置傳參。
* 域名部分會(huì)被過(guò)濾掉;
* 不需要添加一個(gè)前導(dǎo)的反斜杠,因?yàn)槊總€(gè)URL 都有。例如,應(yīng)該是^test 而不是 ^/test;
* 每個(gè)正則表達(dá)式前面的'r' 是可選的但是建議加上,表示字符串中任何字符都不轉(zhuǎn)義;
* 若要從URL 中捕獲一個(gè)值,只需要在它周圍放置一對(duì)圓括號(hào)。
* 任何組匹配的變量,都會(huì)議字符串的形式傳遞給view, 例如通過(guò)([0-9]{4})匹配出了2019,但2019會(huì)被當(dāng)做字符串傳遞給year。
從這里可以看出,視圖的參數(shù)是根據(jù)URL的正則式,按順序匹配并自動(dòng)賦值的。雖然這樣可以實(shí)現(xiàn)任意多個(gè)參數(shù)的傳遞,但是卻不夠靈活,URL看起來(lái)很混亂,而且
由于是正則匹配,有些情況下容易出錯(cuò)。
  • 命名組
    剛才我們?cè)谑褂脠A括號(hào)進(jìn)行傳參的時(shí)候是位置傳參,那么如果我們希望使用關(guān)鍵字傳參的時(shí)候該怎么辦呢?
    這時(shí)候我們就使用到了命名組,命名組的正則表達(dá)式語(yǔ)法是(?P<name>pattern),其中name是指?jìng)鬟f參數(shù)的名字,pattern是指匹配模式。
url('^test/(?P<year>[0-9]{4})/$',views.TestFive.as_view())
class TestFive(View):
    def get(self,request,year):  #入?yún)ear一定要與url中的參數(shù)命一致
        print(year)  #獲取的是傳過(guò)來(lái)的值
        return HttpResponse('TestFive:帶單個(gè)命名參數(shù)的寫法')

url('^test/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',views.TestSix.as_view())
class TestSix(View):
    def get(self,request,year,month,day):
        print(year,month,day)
        return HttpResponse('TestSix:帶多個(gè)命名參數(shù)的寫法')
  • 指定視圖參數(shù)的默認(rèn)值
    利用named group可以為view指定一個(gè)默認(rèn)參數(shù)來(lái)匹配多條規(guī)則。
url(r'^test/$',views.TestFive.as_view()),
url(r'^test/(?P<year>[0-9]{4})/$',views.TestFive.as_view())

class TestFive(View):
    def get(self, request, year = '2010'):
        print('-->===>', self, request, year)
        return HttpResponse('TestFive: 命名組1')
#地址欄輸入http://127.0.0.1:8000/test,調(diào)用TestFive的話,則會(huì)取year默認(rèn)值2010
  • 錯(cuò)誤處理
    當(dāng)Django 找不到一個(gè)匹配請(qǐng)求的URL 的正則表達(dá)式時(shí),或者當(dāng)拋出一個(gè)異常時(shí),Django 將調(diào)用一個(gè)錯(cuò)誤處理視圖。
    每一個(gè)請(qǐng)求,都會(huì)返回一個(gè)HTTP狀態(tài)碼
    200 : 請(qǐng)求正常;
    404:就是找不到頁(yè)面,或者說(shuō)匹配不到對(duì)應(yīng)的path路徑;
    403:是指服務(wù)器拒絕, 一般出現(xiàn)這種情況,是用戶被服務(wù)器拉進(jìn)黑名單,或者安全攔截;
    400:你的request異常,一般就是你的請(qǐng)求缺少內(nèi)容;
    500:服務(wù)器異常,這個(gè)一般就是代碼出現(xiàn)了異常;
    在URLconf中指定參數(shù),這些參數(shù)分別是
    handler404: 一個(gè)callable或一個(gè)字符串,表示如果沒(méi)有URL模式匹配,應(yīng)該調(diào)用的視圖的完整Python導(dǎo)入路徑。默認(rèn)情況下,這是'django.views.defaults.page_not_found'。
    handler500: 默認(rèn)情況下,這是'django.views.defaults.page_not_found'。
    handler403: 默認(rèn)情況下,這是'django.views.defaults.permission_denied'。
    handler400: 默認(rèn)情況下,這是'django.views.defaults.bad_request'。
    可以自定義報(bào)錯(cuò)信息:
handler404 = 'TestApp.views.erropage' #需要app名稱.views.函數(shù)名, 這個(gè)指定的實(shí)際上是一個(gè)引入的路徑。只能調(diào)用函數(shù),不能用類方法
#views.py中
def erropage(request):
    return HttpResponse('not found page')
#settings.py中調(diào)試模式關(guān)閉才能看到自定義的信息
DEBUG = False
image.png
  • 包含其它的URLconfs
    在任何時(shí)候,你的urlpatterns 都可以包含其它URLconf 模塊。這實(shí)際上將一部分URL 放置于其它URL 下面。
#在應(yīng)用app中新建一個(gè)urls.py放置具體的
url(r'^2018/$',views.TestOne.as_view()),
url(r'^(?P<year>[0-9]{4})/$',views.TestFive.as_view()),
url(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.TestSix.as_view()),
url(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.TestSeven.as_view())
#在項(xiàng)目的根 urls.py 配置文件改為:
import views
from django.conf.urls import url,include
url(r'^test/',include('TestApp.urls'))
#如果項(xiàng)目非常龐大,應(yīng)用非常多,應(yīng)用的 URL 都寫在根 urls.py 配置文件中的話,會(huì)顯的非常雜亂,
還會(huì)出現(xiàn)名稱沖突之類的問(wèn)題,這樣對(duì)開(kāi)發(fā)整個(gè)項(xiàng)目是非常不利的??梢赃@樣解決,把每個(gè)應(yīng)用的 URL
寫在它們各自的 urls.py 配置文件里,然后在根 urls.py 里用 include() 函數(shù)引用
  • URL反向解析
    在使用Django 項(xiàng)目時(shí),一個(gè)常見(jiàn)的需求是獲得URL 的最終形式,以用于嵌入到生成的內(nèi)容中(視圖中和顯示給用戶的URL等)或者用于處理服務(wù)器端的導(dǎo)航(重定向等)。
    人們強(qiáng)烈希望不要硬編碼這些URL(費(fèi)力、不可擴(kuò)展且容易產(chǎn)生錯(cuò)誤)或者設(shè)計(jì)一種與URLconf 毫不相關(guān)的專門的URL 生成機(jī)制,因?yàn)檫@樣容易導(dǎo)致一定程度上產(chǎn)生過(guò)期的URL。
    換句話講,需要的是一個(gè)DRY 機(jī)制。除了其它優(yōu)點(diǎn),它還允許設(shè)計(jì)的URL 可以自動(dòng)更新而不用遍歷項(xiàng)目的源代碼來(lái)搜索并替換過(guò)期的URL。
    要獲取一個(gè)URL,最初擁有的信息是負(fù)責(zé)處理它的視圖的標(biāo)識(shí)(例如名字),與查找正確的URL 的其它必要的信息如視圖參數(shù)的類型(位置參數(shù)、關(guān)鍵字參數(shù))和值。
    Django 提供了一個(gè)解決方案使得URL 映射是URL 設(shè)計(jì)唯一的儲(chǔ)存庫(kù)。你用你的URLconf填充它,然后可以雙向使用它:
    1)根據(jù)用戶/瀏覽器發(fā)起的URL 請(qǐng)求,它調(diào)用正確的Django 視圖,并從URL 中提取它的參數(shù)需要的值。
    2) 根據(jù)Django 視圖的標(biāo)識(shí)和將要傳遞給它的參數(shù)的值,獲取與之關(guān)聯(lián)的URL。
    第一種方式是我們?cè)谇懊娴恼鹿?jié)中一直討論的用法。第二種方式叫做反向解析URL、反向URL匹配、反向URL查詢或者簡(jiǎn)單的URL反查。
    在需要URL 的地方,對(duì)于不同層級(jí),Django 提供不同的工具用于URL 反查:
    1)在模板中:使用url 模板標(biāo)簽。
    2)在Python 代碼中:使用django.core.urlresolvers.reverse() 函數(shù)。
    3)在更高層的與處理Django 模型實(shí)例相關(guān)的代碼中:使用get_absolute_url() 方法。
  1. 重定向:
#利用redirect跳轉(zhuǎn)
#主程序urls.py中
from django.conf.urls import url,include
url(r'^test/',include('TestApp.urls'))
#應(yīng)用程序urls.py中
import views
url(r'^2018/$',views.TestOne.as_view()),
url(r'^visit/(?P<flag>[0-9]{1})$',views.Visit.as_view())
#views.py中
from django.shortcuts import render,redirect
class Visit(View):
    def get(self,request,flag):
        #這是一個(gè)重定向方法
        #如果需要在這做一個(gè)跳轉(zhuǎn)
        if flag == '1':
            return HttpResponse('hello success!')
        else:
            return redirect('/test/2018')   #重定向跳一個(gè)地址, 因?yàn)閡rl地址開(kāi)始肯定是一個(gè)/,  如果你不帶斜杠的話,它就會(huì)當(dāng)成一個(gè)相對(duì)地址,它自會(huì)自動(dòng)在當(dāng)前的url中往后添加。
  1. URL 的反向解析
    URL反向解析一般是通過(guò)[reverse函數(shù)]使用django.core.urlresolvers.reverse() 函數(shù),以及模板中的url標(biāo)記實(shí)現(xiàn)。
  • 未帶參數(shù)
url(r'^visit/(?P<flag>[0-9]{1})$',views.Visit.as_view())
url(r'^2018/$',views.TestOne.as_view(),name='login'),
#views.py
class TestOne(View):
    def get(self,request):
        print('-->===>',self,request)
        return HttpResponse('TestOne:普通用法')
class TestOne(View):
    def get(self,request):
        print('-->===>',self,request)
        return HttpResponse('TestOne:普通用法')
class Visit(View):
    def get(self,request,flag):
        #這是一個(gè)重定向方法
        #如果需要在這做一個(gè)跳轉(zhuǎn)
        if flag == '1':
            return HttpResponse('hello success!')
        else:
            # reverse未帶參數(shù)
            return redirect(reverse('login'))
  • 帶非命名參數(shù)的跳轉(zhuǎn)
url(r'^visit/(?P<flag>[0-9]{1})$',views.Visit.as_view()),
url(r'^([0-9]{4})/([0-9]{2})/([0-9]{2})$', views.TestFour.as_view(),name='login3')

class Visit(View):
    def get(self,request,flag):
        #這是一個(gè)重定向方法
        #如果需要在這做一個(gè)跳轉(zhuǎn)
        if flag == '1':
            return HttpResponse('hello success!')
        else:
            # reverse
            return redirect(reverse('login3',args=("2018", "03","21")))
class TestFour(View):
    def get(self, request, year,month,day):
        print('-->===>', self, request, year,month,day)
        return HttpResponse('TestFour: 3個(gè)非命名參數(shù)')
  • 命名參數(shù)的跳轉(zhuǎn)
#主urls.py
url(r'^test/',include('TestApp.urls')) 
#應(yīng)用urls.py
url(r'^visit/(?P<flag>[0-9]{1})/$',views.Visit.as_view()),
url(r'^login/(?P<username>[a-z]{3})/$', views.Login.as_view(),name='regist')
#views.py
class Visit(View):
    def get(self,request,flag):
        if flag =='1':
            return HttpResponse('登錄成功')
        else:
            return redirect(reverse('regist',kwargs={'username':'llp'}))
class Login(View):
    def get(self,request,username):
        message = '{} please login'.format(username)
        return HttpResponse(message)
總結(jié):如果url里面帶了無(wú)名或者有名參數(shù),那么在重定向時(shí),reverse需要帶上args或者kwargs。
  • URL 模式的命名
    為了完成上面例子中的URL 反查,你將需要使用命名的URL 模式。URL 的名稱使用的字符串可以包含任何你喜歡的字符。并不僅限于合法的Python 名稱。
    當(dāng)命名你的URL 模式時(shí),請(qǐng)確保使用的名稱不會(huì)與其它應(yīng)用中名稱沖突。如果你的URL 模式叫做comment,而另外一個(gè)應(yīng)用中也有一個(gè)同樣的名稱,當(dāng)你在模板中使用這個(gè)名稱的時(shí)候不能保證將插入哪個(gè)URL。
    在URL 名稱中加上一個(gè)前綴,比如應(yīng)用的名稱,將減少?zèng)_突的可能。我們建議使用myapp-comment 而不是comment。
  • URL 命名空間
    為什么需要命名空間呢?
    在之前如果我們通過(guò)URL反查的話是通過(guò)URL模式中的name屬性來(lái)進(jìn)行反查標(biāo)記的,但是name屬性容易重復(fù)并且不利于復(fù)用,當(dāng)我們要多次部署一個(gè)URL配置模塊的時(shí)候,就無(wú)法通過(guò)簡(jiǎn)單的name屬性來(lái)進(jìn)行標(biāo)記了。
    一般來(lái)說(shuō),同一應(yīng)用下的不同實(shí)例應(yīng)該具有相同的應(yīng)用命名空間,但是,這并不意味著不同應(yīng)用可以使用相同的實(shí)例命名空間,因?yàn)閷?shí)例命名空間在你所有項(xiàng)目中都是唯一的。
  • 反查帶命名空間的URL
    當(dāng)解析一個(gè)帶命名空間的URL(例如'polls:index')時(shí),Django 將切分名稱為多個(gè)部分,然后按下面的步驟查找:
    1)首先,Django 查找匹配的應(yīng)用命名空間(在這個(gè)例子中為'polls')。這將得到該應(yīng)用實(shí)例的一個(gè)列表。
    2)如果有一個(gè)當(dāng)前應(yīng)用被定義,Django 將查找并返回那個(gè)實(shí)例的URL 解析器。當(dāng)前應(yīng)用可以通過(guò)請(qǐng)求上的一個(gè)屬性指定。
    3)當(dāng)前應(yīng)用還可以通過(guò)reverse() 函數(shù)的一個(gè)參數(shù)手工設(shè)定。
    4)如果沒(méi)有當(dāng)前應(yīng)用。Django 將查找一個(gè)默認(rèn)的應(yīng)用實(shí)例。默認(rèn)的應(yīng)用實(shí)例是實(shí)例命名空間 與應(yīng)用命名空間 一致的那個(gè)實(shí)例(在這個(gè)例子中,polls 的一個(gè)叫做'polls' 的實(shí)例)。
    5)如果沒(méi)有默認(rèn)的應(yīng)用實(shí)例,Django 將挑選該應(yīng)用最后部署的實(shí)例,不管實(shí)例的名稱是什么。
    6)如果提供的命名空間與第1步中的應(yīng)用命名空間 不匹配,Django 將嘗試直接將此命名空間作為一個(gè)實(shí)例命名空間查找。
    7)如果有嵌套的命名空間,將為命名空間的每個(gè)部分重復(fù)調(diào)用這些步驟直至剩下視圖的名稱還未解析。然后該視圖的名稱將被解析到找到的這個(gè)命名空間中的一個(gè)URL。

如果name是唯一的時(shí)候,你可以直接只使用name,但是如果name在其它include中也存在相同name,為了區(qū)分,我們可以給inlude設(shè)置一個(gè)namespace
我們通過(guò)命名空間名稱+名稱訪問(wèn)。
為了程序的健壯性,我們盡量使用命名空間+名稱訪問(wèn)
頂層其實(shí)有一個(gè)app名稱,但是我們?nèi)粘i_(kāi)發(fā)中,幾乎不使用,該功能了解知道即可

#主urls.py
#namespace只有在有多個(gè)include時(shí),才需要
#namespace 與name的設(shè)置規(guī)則一樣,同一級(jí)別,名稱需要保持唯一
url(r'^test/',include('TestApp.urls',namespace='test'))
#應(yīng)用下的urls.py
url(r'^visit/(?P<flag>[0-9]{1})$',views.Visit.as_view()),
url(r'^2018/$',views.TestOne.as_view(),name='login')
#views.py
class Visit(View):
    def get(self,request,flag):
        #這是一個(gè)重定向方法
        #如果需要在這做一個(gè)跳轉(zhuǎn)
        if flag == '1':
            return HttpResponse('hello success!')
        else:
            return redirect(reverse('test:login')) 
#如果url寫了namespace,則這里需要namespace:name形式,否則報(bào)錯(cuò);

class TestOne(View):
    def get(self,request):
        print('-->===>',self,request)
        return HttpResponse('TestOne:普通用法')

地址欄輸入:http://127.0.0.1:8000/test/visit/0會(huì)重定向到http://127.0.0.1:8000/test/2018/

image.png

url(r'^test/',include('TestApp.urls',namespace='visit'))

url(r'^visit/(?P<flag>[0-9]{1})/$',views.Visit.as_view()),
url(r'^login/(?P<username>[a-z]{3})/$', views.Login.as_view(),name='regist')

class Visit(View):
    def get(self,request,flag):
        if flag =='1':
            return HttpResponse('登錄成功')
        else:
            print(reverse('visit:regist',kwargs={'username':'llp'}))
            return redirect(reverse('visit:regist',kwargs={'username':'llp'}))

class Login(View):
    def get(self,request,username):
        message = '{} please login'.format(username)
        return HttpResponse(message)
#輸入
http://127.0.0.1:8000/test/visit/0=>跳轉(zhuǎn)到http://127.0.0.1:8000/test/login/llp/
打印出來(lái)的是:llp please login
要記住reverse這個(gè)函數(shù)其實(shí)就是返回一個(gè)字符串/test/login/llp/。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容