Django-02.url、錯誤處理以及命名空間

1.Django 如何處理一個請求

  • Django 決定要使用的根URLconf 模塊。一般,這個值就是ROOT_URLCONF 的設置,可是若是進來的HttpRequest對象具備一個urlconf 屬性(經過中間件request processing 設置),則使用這個值來替換ROOT_URLCONF設置。
  • Django 加載該Python 模塊並尋找可用的urlpatterns。它是django.conf.urls.url()
    實例的一個Python 列表。
  • Django 依次匹配每一個URL 模式,在與請求的URL 匹配的第一個模式停下來。 一旦其中的一個正則表達式匹配上,Django將導入並調用給出的視圖,它是一個簡單的Python 函數(或者一個基於類的視圖)。視圖將得到以下參數: 一個HttpRequest 實例。
  • 若是匹配的正則表達式返回了沒有命名的組,那麼正則表達式匹配的內容將做爲位置參數提供給視圖。關鍵字參數由正則表達式匹配的命名組組成,可是能夠被django.conf.urls.url()的可選參數kwargs覆蓋。
  • 若是沒有匹配到正則表達式,或者若是過程當中拋出一個異常,Django 將調用一個適當的錯誤處理視圖。

2.URL解釋:

schema://host[:port#]/path/.../?query-stringpython

  • schema:指定使用的協議(例如:http, https, ftp)
  • host:Http服務器的IP地址或者域名
  • port:端口號,默認是80端口
  • path:訪問資源的路徑
  • query-string:發送給http服務器的數據
  • anchor:錨點

3.URL中的正則

url(r'^test1/9999/$', views.test1.as_view()),                #普通用法
url(r'^test2/([0-9]{4})/$', views.test2.as_view()),        # 單個非命名參數
url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.test3.as_view()),
url(r'^test4/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.test4.as_view()),

咱們先開始建一個django工程 在這裏咱們給給工程命名爲lesson1 放在Django_lesson文件夾下
具體建django工程的細節詳情見Django-0一、初識Django和搭建Django helloworld正則表達式

而後新建一個app 名爲urltestdjango

在lesson1.url.py 中導入viewsegmentfault

from urltest import views

4.非命名參數

在lesson.urls.py中添加如下路由瀏覽器

url(r'^admin/', admin.site.urls),
    url(r'^test1/9999/$', views.Test1.as_view()),
    url(r'^test2/([0-9]{4})/$', views.Test2.as_view()),
    url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.Test3.as_view()), views.Test4.as_view()),

在urltest.view.py中添加如下視圖類服務器

class Test1(View):
    def get(self, request):
        msg = "Test1 sucessful"
        return HttpResponse(msg)


class Test2(View):
    def get(self, request, year):
        msg = "Test2 sucessful  %s 年" % year
        return HttpResponse(msg)


class Test3(View):
    def get(self, request, year, month):
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)

注:
若要從URL 中捕獲一個值,只須要在它周圍放置一對圓括號。
不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles。
每一個正則表達式前面的'r' 是可選的可是建議加上。它告訴Python 這個字符串是「原始的」 —— 字符串中任何字符都不該該轉義。參見Dive Into Python 中的解釋。app

^表明開始匹配,若是隻有^符號,則只須要部分匹配成功便可
$表明結束匹配,添加$符號, 通常就表明完整匹配less

咱們的URL匹配規則必定須要保持惟一函數

5.命名參數

上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。
在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern),其中name 是組的名稱,pattern 是要匹配的模式。工具

url(r'^test4/(?P<year>[0-9]{4})/$', views.Test4.as_view()),
    url(r'^test5/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.Test5.as_view()),

在urltest.view.py中添加如下視圖類

class Test4(View):
    def get(self, request, year):
        msg = "Test3 sucessful %s 年" % year
        return HttpResponse(msg)


class Test5(View):
    def get(self, request, month, year):  # 這裏咱們交換了year和month的順序
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

若是有命名參數,則使用這些命名參數,忽略非命名參數。
不然,它將以位置參數傳遞全部的非命名參數。
請求的URL被看作是一個普通的Python 字符串, URLconf在其上查找並匹配。進行匹配時將不包括GET或POST請求方式的參數以及域名。換句話講,全部的請求方法 —— 即,對同一個URL的不管是POST請求、GET請求、或HEAD請求方法等等 —— 都將路由到相同的函數。
每一個捕獲的參數都做爲一個普通的Python 字符串傳遞給視圖,不管正則表達式使用的是什麼匹配方式。

包含其它的URLconfs

在任什麼時候候,你的urlpatterns 均可以包含其它URLconf 模塊。這實際上將一部分URL 放置於其它URL 下面。
在lesson1.urls.py中加入如下代碼

from django.conf.urls import include  # 導入 include
    url(r'^test7/', include('urltest.urls')),  # 加入路由

在urltest文件夾下新建urls.py加入如下代碼

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^test7/$', views.Test7.as_view()),
]

在urltest.views.py加入如下視圖類

class Test7(View):
    def get(self, request):  # 這裏咱們交換了year和month的順序
        msg = "Test7 sucessful"
        return HttpResponse(msg)

傳遞額外的選項給視圖函數

URLconfs 具備一個鉤子,讓你傳遞一個Python 字典做爲額外的參數傳遞給視圖函數。
django.conf.urls.url() 函數能夠接收一個可選的第三個參數,它是一個字典,表示想要傳遞給視圖函數的額外關鍵字參數。

#lesson1.urls.py中加入這個路由
url(r'^test8/', include('urltest.urls'), {'name': 'lethe', 'date': '2018'}),

#urltest.urls.py中加入這個路由
url(r'^test8/$', views.Test8.as_view()),

#views.py中加入這個視圖類
class Test8(View):
    def get(self, request, name, date):  # 這裏咱們交換了year和month的順序
        msg = "Test8 sucessful by %s in %s" % (name, date)
        return HttpResponse(msg)

這裏寫圖片描述

6.錯誤處理

當Django 找不到一個匹配請求的URL 的正則表達式時,或者當拋出一個異常時,Django 將調用一個錯誤處理視圖。

Http狀態碼
每個請求,都會返回一個狀態
200 : 請求正常
404:找不到頁面
403:是指服務器拒絕
400:request異常
500:服務器異常

在URLconf中指定參數,這些參數分別是

handler404
一個callable或一個字符串,表示若是沒有URL模式匹配,應該調用的視圖的完整Python導入路徑。
默認狀況下是'django.views.defaults.page_not_found'。

handler500
一個callable或一個字符串,表示若是沒有URL模式匹配,應該調用的視圖的完整Python導入路徑。
默認狀況下,這是'django.views.defaults.page_not_found'。

handler403
一個callable或一個字符串,表示若是用戶沒有訪問資源所需的權限,應調用的視圖的完整Python導入路徑。
默認狀況下,這是'django.views.defaults.permission_denied'。

handler400
若是HTTP客戶端已發送致使錯誤條件的請求和狀態代碼爲400的響應,則應調用的可調用或表示完整的Python視圖導入路徑的字符串。
默認狀況下,這是'django.views.defaults.bad_request'。

在settings.py中將DEBUG值改成True
當找不到頁面的時候 頁面顯示以下圖
這裏寫圖片描述
而後咱們再在settings.py中將DEBUG值改成False (咱們通常在開發的時候設置DEBUG值爲True 在產品上線的時候將DEBUG值改成False)
當找不到頁面的時候 頁面顯示以下圖
這裏寫圖片描述

咱們將代碼做以下更改

#在views.py中加入如下代碼
def Error404(request):
    return HttpResponse("哎呦 404 尷尬了!")

#DEBUG值保持爲False
#在lesson1.py中加入
handler404 = 'urltest.views.Error404'

這裏寫圖片描述

7.URL 的反向解析

在使用Django 項目時,一個常見的需求是得到URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。
人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。
換句話講,須要的是一個DRY 機制。除了其它優勢,它還容許設計的URL 能夠自動更新而不用遍歷項目的源代碼來搜索並替換過時的URL。
要獲取一個URL,最初擁有的信息是負責處理它的視圖的標識(例如名字),與查找正確的URL 的其它必要的信息如視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供了一個解決方案使得URL 映射是URL 設計惟一的儲存庫。你用你的URLconf填充它,而後能夠雙向使用它:
根據用戶/瀏覽器發起的URL 請求,它調用正確的Django 視圖,並從URL 中提取它的參數須要的值。
根據Django 視圖的標識和將要傳遞給它的參數的值,獲取與之關聯的URL。
第一種方式是咱們在前面的章節中一直討論的用法。第二種方式叫作反向解析URL、反向URL匹配、反向URL查詢或者簡單的URL反查。
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:
在模板中:使用url 模板標籤。
在Python 代碼中:使用django.core.urlresolvers.reverse() 函數。
在更高層的與處理Django 模型實例相關的代碼中:使用get_absolute_url() 方法。

#在urls.views.py中加入如下代碼
    url(r'^articles/$', views.Articles.as_view()),
    #在views.py中加入如下代碼
    class Articles(View):
    def get(self, request):
        return redirect('/test1/9999/')

這裏寫圖片描述

7.URL 命名空間

URL 命名空間容許你反查到惟一的命名URL 模式,即便不一樣的應用使用相同的URL 名稱。第三方應用始終使用帶命名空間的URL 是一個很好的實踐(咱們在教程中也是這麼作的)。相似地,它還容許你在一個應用有多個實例部署的狀況下反查URL。換句話講,由於一個應用的多個實例共享相同的命名URL,命名空間提供了一種區分這些命名URL 的方法。

一個URL命名空間有兩個部分,它們都是字符串:
應用命名空間
它表示正在部署的應用的名稱。一個應用的每一個實例具備相同的應用命名空間。例如,能夠預見Django 的管理站點的應用命名空間是'admin'。
實例命名空間
它表示應用的一個特定的實例。實例的命名空間在你的所有項目中應該是惟一的。可是,一個實例的命名空間能夠和應用的命名空間相同。它用於表示一個應用的默認實例。
URL 的命名空間使用':' 操做符指定。例如,管理站點應用的主頁使用'admin:index'。它表示'admin' 的一個命名空間和'index' 的一個命名URL。
命名空間也能夠嵌套。命名URL'sports:polls:index' 將在命名空間'polls'中查找'index',而poll 定義在頂層的命名空間'sports' 中。

#在lesson1.urls.py中加入如下路由
    url(r'^url1test/', include('urltest.urls_1', namespace='url1test')),
    url(r'^url2test/', include('urltest.urls', namespace='url2test')),
    url(r'^url1_login/$', views.ToUrl1Login.as_view()),
    url(r'^url2_login/$', views.ToUrl2Login.as_view()),
    
    #在urltest文件夾下新建url_1.py並加入如下代碼
    from django.conf.urls import url
    from urltest import views
    urlpatterns = [
    url(r'^login/$', views.Url1Login.as_view(), name='login'),
]

    #在urltest.url.py中加入如下路由
    url(r'^login/$', views.Url2Login.as_view(), name='login'),
    
    # 在views.py中加入如下視圖類
    class Url1Login(View):
    def get(self, request):
        return HttpResponse("我是url1test.login")


class Url2Login(View):
    def get(self, request):
        return HttpResponse("我是url2test.login")


class ToUrl1Login(View):
    def get(self, request):
        return redirect(reverse('url1test:login'))


class ToUrl2Login(View):
    def get(self, request):
        return redirect(reverse('url2test:login'))

這裏寫圖片描述

這裏寫圖片描述

當輸入/url1_login/時 跳到ToUrl1Login而後跳到url1test:login(即namespace='url1test',name='login'的路由 即/url1test/login/ 打印我是url1test.login)


8.附錄 本文章代碼:

view.py

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
from django.shortcuts import reverse, redirect
# Create your views here.


class Test1(View):
    def get(self, request):
        msg = "Test1 sucessful"
        return HttpResponse(msg)


class Test2(View):
    def get(self, request, year):
        msg = "Test2 sucessful  %s 年" % year
        return HttpResponse(msg)


class Test3(View):
    def get(self, request, year, month):
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)


class Test4(View):
    def get(self, request, year):
        msg = "Test4 sucessful %s 年" % year
        return HttpResponse(msg)


class Test5(View):
    def get(self, request, month, year):  # 這裏咱們交換了year和month的順序
        msg = "Test5 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)


class Test6(View):
    def get(self, request, num='1'):  # 這裏咱們交換了year和month的順序
        msg = "Test6 sucessful num=%s" % num
        return HttpResponse(msg)


class Test7(View):
    def get(self, request):  # 這裏咱們交換了year和month的順序
        msg = "Test7 sucessful"
        return HttpResponse(msg)


class Test8(View):
    def get(self, request, name, date):  # 這裏咱們交換了year和month的順序
        msg = "Test8 sucessful by %s in %s" % (name, date)
        return HttpResponse(msg)


class Articles(View):
    def get(self, request):
        return redirect('/test1/9999/')

class Reverse_test(View):
    def get(self, request):
        return redirect(reverse('reverse_test', args=('2021',)))


class Url1Login(View):
    def get(self, request):
        return HttpResponse("我是url1test.login")


class Url2Login(View):
    def get(self, request):
        return HttpResponse("我是url2test.login")


class ToUrl1Login(View):
    def get(self, request):
        return redirect(reverse('url1test:login'))


class ToUrl2Login(View):
    def get(self, request):
        return redirect(reverse('url2test:login'))

def Error404(request):
    return HttpResponse("哎呦 404 尷尬了!")

lesson1.urls.py

from django.conf.urls import url, include
from django.contrib import admin
from urltest import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test1/9999/$', views.Test1.as_view()),
    url(r'^test2/([0-9]{4})/$', views.Test2.as_view(), name='reverse_test'),
    url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.Test3.as_view()),
    url(r'^test4/(?P<year>[0-9]{4})/$', views.Test4.as_view()),
    url(r'^test5/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.Test5.as_view()),
    url(r'^test6/(?P<num>[0-9]+)/$', views.Test6.as_view()),
    url(r'^test7/', include('urltest.urls')),
    url(r'^test8/', include('urltest.urls'), {'name': 'lethe', 'date': '2018'}),
    url(r'^articles/$', views.Articles.as_view()),
    url(r'^reverse/$', views.Reverse_test.as_view()),

    url(r'^url1test/', include('urltest.urls_1', namespace='url1test')),
    url(r'^url2test/', include('urltest.urls', namespace='url2test')),
    url(r'^url1_login/$', views.ToUrl1Login.as_view()),
    url(r'^url2_login/$', views.ToUrl2Login.as_view()),

]

handler404 = 'urltest.views.Error404'

urltest.urls.py

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^test7/$', views.Test7.as_view()),
    url(r'^test8/$', views.Test8.as_view()),
    url(r'^login/$', views.Url2Login.as_view(), name='login'),
]

urls_1.py

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^login/$', views.Url1Login.as_view(), name='login'),
]

目錄結構

這裏寫圖片描述

注: 本文章是本人的CSDN博客中對應的文章轉過來的

相關文章
相關標籤/搜索