日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Django(二) 路由和视图

發布時間:2025/3/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Django(二) 路由和视图 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

路由定義

路由是客戶端訪問的url路徑與視圖函數間的一一映射關系。Django中的路由關系在urls.py文件中,基本格式如下:

urlpatterns = [url(regex,view, kwargs=None, name=None), ]

參數說明:
regex: 匹配url路徑的正則表達式,比如r'^login/', 匹配以login/開頭的路徑,當你在瀏覽器地址欄輸入http://127.0.0.1/login/時,會調用login映射的視圖函數來處理請求。幾點提醒,
1. 為了避免轉義,正則的前面最好加上r;
2. 路徑前默認都有前導的反斜杠/,我們在正則中就不需要再加了,比如r'login/'就可以,而不用r'^/login/';
3. 如果我們訪問127.0.0.1:8000/login,login后未加反斜杠/,將會重定向至127.0.0.1:8000/login/,這時因為默認設置APPEND_SLASH = True。另外,任何未在setting.py文件中定義的配置都由django.conf.global_settings 提供
4. 在進行url路徑匹配時,只要匹配成功一個,就不在向下匹配。
view: 映射的視圖函數
name: 可以為視圖函數定義別名,這個稍后介紹。
配置根目錄:
我們必須為項目配置根目錄,即當用戶訪問的url不帶路徑時,必須有相應的視圖函數處理并返回響應,而不是錯誤頁面。加入下面的路由:
url(r'^$', view) 當匹配路徑為空,調用指定的視圖函數處理。

路徑分組和視圖函數傳參

分組是正則中的操作,對正則表達式加括號,就可以實現路徑分組。分組的目的是為了給視圖函數傳參。這里有兩種分組方式,通過位置傳參的簡單分組,和通過關鍵字傳參的命名分組。我們通過下面的栗子來介紹這兩種分組方式。
1.新建一個項目learn, 并創建應用calc, 在calc的視圖函數中定義一個計算加法的函數add:

from django.http import HttpResponse # HttpResponse用于直接返回字符串響應 def add(request,a,b):# add 函數除了第一個請求對象參數,還從urls.py中的路由接收另外兩個參數用于求和c = int(a) + int(b)return HttpResponse('{a} + = {c}'.format(a=a, b=b, c=str(c)))

2.在項目的urls.py中編輯路由映射:
2.1 簡單分組:

from django.conf.urls import url from django.contrib import admin from calc import views as calc_viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^add/(\d+)/(\d+)/', calc_views.add),# 簡單分組:通過圓括號匹配兩組數字,作為參數傳給視圖函數add ]

2.2 命名分組:

from django.conf.urls import url from django.contrib import admin from calc import views as calc_viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^add/(?P<c>\d+)/(?P<b>\d+)/', calc_views.add),# 通過(?P<...>)命名分組, 將分組名a和b傳給視圖函數add中的關鍵字參數a和b,# 分組名必須和關鍵字匹配:如果分組名為x,y 而視圖的關鍵字是a,b,就會報錯。 ]

3.在瀏覽器地址欄輸入http://127.0.0.1:8000/add/4/5/,你將看到以下結果:

4.另外,如果不用分組,可以通過url中的query string查詢字符串來提取數字,進行計算。
因此url需要使用查詢字符串形式:
http://127.0.0.1:8000/add/?a=4&b=5
urls路由如下:

urlpatterns = [url(r'^add/$', calc_views.add, name='add'), ]

視圖函數中提取查詢字符串:

def add(request):a = request.GET.get('a') # get請求中查詢字符串以字典鍵值對的方式封裝在request對象中b = request.GET.get('b')c = int(a) + int(b)return HttpResponse('{a} + = {c}'.format(a=a, b=b, c=str(c)))

別名

通過別名還原真實url是很有幫助的,尤其是urls.py路由中的url路徑修改后,如果不使用別名,我們就不得不在所有直接使用了url路徑的地方一一修改。
比如,在模板的表單提交中,如果action的路徑寫死了,一旦我們修改了urls.py中的路徑,那么客戶端的表單提交路徑就是無效的,除非我們手動修改action路徑。

<form action="path" method="post">

通過使用別名,可以避免這種情況發生。
1.定義別名

urlpatterns = [url(r'^login/$', blog_views.login, name='login')# name='login', 為這條路由起個別名'login', 通過別名可以得到對應的網址 ]

2.使用別名:{% url 'name' %}

<form action="{% url 'name' %}" method="post">

還有以一種情況是,用戶收藏了我們的舊網址127.0.0.1/index/,現在網站的網址變了127.0.0.1/index_new/,用戶如何通過舊網址找到我們的網站。
解決方案是為舊網址寫一個跳轉函數:
1.編輯視圖函數

from django.http import HttpResponseRedirect from django.urls import reversedef to_new_index(request):return HttpResponseRedirect(reverse(index))# reverse()函數,可以接收一個視圖函數,并返回該視圖函數對應的url# 返回重定向響應def index(request): # return render(request, 'index.html')

2.編輯路由

from django.conf.urls import url from blog import views as blog_views # 從blog應用中導入視圖函數urlpatterns = [url(r'^index_new/$', blog_views.index),url(r'^index/$',blog_views.to_new_index),# 如果url路徑是/index,那么調用視圖函數to_new_index, 跳轉至新的url ]

3.這樣我們在瀏覽中輸入127.0.0.1/index/,將自動跳轉到127.0.0.1/index_new/

路由分發

前面我們都是在項目文件夾的urls.py中通過from app import views這種形式導入視圖函數,然后定義具體路由。應該知道的是,項目目錄中的urls.py是全局路由,我們要避免將具體應用的路由寫在全局路由中,這樣會造成代碼耦合,而且:1. 當應用越來越多,全局路由將越來越大,不利于維護;2.一旦某一條路由崩潰了,將導致整個路由都崩潰。正確的方式是在每個應用自己的文件夾中定義自己的路由,全局路由只負責做分發。下面我們看一下如何實現。
1.在應用文件夾中新建urls.py,編輯路由規則

from django.conf.urls import url from . import views # 從當前文件夾導入視圖函數urlpatterns = [url(r'^login/$',views.login, name='login'),url(r'^index/$',views.index, name='index'), ]

2.在全局路由中作分發

from django.conf.urls import url, include # 導入include函數 from django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# include創建路由分發url(r'^polls/', include('polls.urls')),# 客戶端在訪問時,只要是屬于polls應用的路徑,就會被分發到polls應用下的路由 ]

注意:
1. 路由分發不能加$結尾約束, 否則直接終止匹配了,造成分發失敗。
2. 如果要作一個空路徑的默認路由分發,可以通過以下方式:

from django.conf.urls import url, include from api import urls as api_urls from web import urls as web_urlsurlpatterns = [url(r'^api/', include(api_urls)), # api開頭的分發至api應用的路由url(r'^', include(web_urls)) # 為空,分發至web應用的路由# 路由分發不能加$, 否則終止了 ]


這樣,我們在瀏覽器中輸入url:http://127.0.0.1:8000/polls/index/,全局路由匹配到是訪問polls應用的,將這條url分發到polls下的urls.py來處理。
后續創建了新的應用,就可以定義各自的路由,然后在全局路由中新增一條分發就可以了。

反向路由

reverse

reverse函數可以接收路由中定義的別名或視圖函數名,反向生成該視圖的url;

導入:from django.shortcuts import reverse

  • 通過別名反向生成:

    urlpatterns = [url(r'^index/$',views.index, name='index'), ]url = reverse('index')
  • 通過視圖函數反向生成:

    def index(request): return render(request, 'index.html')url = reverse(index)
  • 接收簡單分組的參數,args=():

    urlpatterns = [url(r'^add/(\d+)/(\d+)/', view.add, name='add'), ]url = reverse(url = reverse('add', args=(2, 9)))
  • 接收命名分組的參數,kwargs=():

    urlpatterns = [url(r'^add/(?P<a>\d+)/(?P<b>\d+)/', view.add, name='add'), ]url = reverse(url = reverse('add', kwargs=(a=2, b=9)))
  • include路由分發和namespace

    在項目的urls.py中經常通過include函數作路由分發,查看源碼可以發現include函數的本質返回了一個元組:(urlconf_module, app_name, namespace),urlconf_module是一個個路由組成的列表;還有有一個值是namespace名稱空間,它的作用是在別名重復時,作區分用的。因此,如果有名稱空間,那么反向路由時需要加名稱空間,比如namespace=’xxx’, name=’yyy’,那么通過reverse函數反向路由時,格式為:reverse('xxx:yyy')。如果嵌套了多層名稱空間,需要由外到里用冒號:連接起來。

    模板中:{% url %}

    在模板中,我們可以通過{% url %}配合別名來反向生成url:

  • 一般形式,通過別名生成:

    {% url 'name' %}
  • 接收簡單分組參數:

    {% url 'name' arg1, arg2 %}
  • 接收命名分組的參數:

    {% url 'name' arg1=xx, arg2=xx %}
  • 視圖函數

    視圖函數是應用的業務處理邏輯。它接收wsgi封裝的客戶端請求對象,返回響應。

    request請求

    request請求對象是視圖函數必須接收的第一個參數。通過調用request的屬性/方法,可以獲取請求信息:
    - request.method 獲取請求方法(GET/POST)
    - request.GET 字典的形式存放GET請求的數據,通過val = request.GET.get(key)可以獲取具體的值
    - request.POST 字典形式存放POST請求的數據,通過val = request.GET.get(key)可以獲取具體的值
    - request.META 獲取請求的所有元信息,比如獲取訪問前的地址(執行完某些操作,比如登錄后,可利用該地址跳轉回去):

    next_url = request.META.get('HTTP_REFERER', '/')
    • request.FILE 獲取上傳的文件

    響應方法

    • render(request, 'template', {key: value, ... }) 渲染模板,返回HttpResponse響應。{key:value}稱為context上下文對象,key對應模板中的變量名,value對應視圖中的對象,渲染時,將視圖函數中的對象嵌入模板中。
    • HttpResponse(' ') 字符串對象
    • redirect('path') 重定向,接收的參數是路徑。會在響應頭中加一個location鍵,客戶端拿到這個鍵對應的值,即url, 對url發起get請求。

    注意redirect和render的區別:
    1. 客戶端收到redirect重定向響應后,會對重定向的url發起get請求,這時會重走路由映射,調用視圖函數。
    2. 而render是直接渲染html模板,生成html頁面,返回給客戶端。

    FBV $ CBV

    簡介

    路由分為兩種:FBV & CBV

    一般我們寫的視圖函數屬于FBV, 請求過來執行視圖函數,函數式編程;

    而CBV,請求過來,執行的是views.py 中定義的類,面型對象的編程方式;

    urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^index.html$', views.IndexView.as_view()), # CBV# 早先的web服務就是提供一個靜態HTML頁面,不涉及ORM和模板渲染,這里寫成這種形式,'^index.html$' 是url偽靜態 ]

    在CBV路由中,要特別注意類名后加as_view()

    自定義CBV:

    from django.views import View class IndexView(View): # 自定義的類繼承Viewdef get(self,request,*args,**kwargs):return render(request, 'index.html') def post(self,request,*args,**kwargs):return HttpResponse('ok')

    請求經過路由到達自定義類后,根據請求方法,來執行get或post函數,這一點是通過反射完成的。查看源碼可以看到所有可以反射的方法:

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] # 如果是通過Ajax發送請求,那么支持以上所以方法

    反射操作是在View類中的dispatch方法中完成的:

    def dispatch(self, request, *args, **kwargs):if request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(), self.http_method_not_allowed)else:handler = self.http_method_not_allowedreturn handler(request, *args, **kwargs)

    從以上源碼可以看到,請求方法執行結果最終是作為dispatch方法的返回值,因此上面我們自定義的CBA可以寫成如下形式:

    from django.views import View class IndexView(View): # 自定義的類繼承View# 重用父類中的dispatch方法,并加入自定義邏輯,比如用戶驗證def dispatch(self, request, *args, **kwargs):if not request.session.get('user-info'):return redirect('/login.html')return super(IndexView, self).dispatch(request,*args,**kwargs)def get(self,request,*args,**kwargs):return render(request, 'index.html')def post(self,request,*args,**kwargs):return HttpResponse('ok')

    CBV中使用裝飾器

    導入:

    from django.utils.decorators import method_decorator

    三種加裝飾的方式:

    假設定義了一個裝飾器deco:

    def deco(func):def wrapper(*args,**kwargs):print('do something')return func(*args,**kwargs)return wrapper
  • 加到請求方法上:

    class LoginView(View):@method_decorator(deco)def get(self,request):return render(request,'login.html')
  • 加到dispatch上:

    class LoginView(View):@method_decorator(deco)def dispatch(self, request, *args, **kwargs):return super(LoginView,self).dispatch(request, *args, **kwargs)
  • 加到類上:

    @method_decorator(deco, name='get') # 指定給get方法加# @method_decorator(deco, name='put')# 必須指定name; 如果有多個方法要裝飾,并列寫class LoginView(View):def get(self,request):return render(request,'login.html')
  • 我們知道Django的中間件中做了一個全局的csrf保護,但是有時我們希望具體對待,那么可以導入csrf裝飾器來實現這個需求:

    from django.views.decorators.csrf import csrf_exempt,csrf_protect

    其中csrf_exempt是不應用csrf保護;csrf_protect是應用csrf保護;我們就可以根據需要加到具體的視圖上了:

    @csrf_protect def demo(request):print('DEMO')return HttpResponse('ok')

    但是,在目前的Django版本中要注意,如果是CBV,那么csrf裝飾器只能加在類中的dispatch方法上:

    class LoginView(View):@method_decorator(csrf_exempt)def dispatch(self, request, *args, **kwargs):return super(LoginView,self).dispatch(request, *args, **kwargs)

    總結

    以上是生活随笔為你收集整理的Django(二) 路由和视图的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。