溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Django基礎(chǔ)三之視圖函數(shù)的使用方法

發(fā)布時(shí)間:2020-09-17 17:05:28 來(lái)源:腳本之家 閱讀:257 作者:愛(ài)文飛翔 欄目:開(kāi)發(fā)技術(shù)

一 Django的視圖函數(shù)view

一個(gè)視圖函數(shù)(類),簡(jiǎn)稱視圖,是一個(gè)簡(jiǎn)單的Python 函數(shù)(類),它接受Web請(qǐng)求并且返回Web響應(yīng)。

響應(yīng)可以是一張網(wǎng)頁(yè)的HTML內(nèi)容,一個(gè)重定向,一個(gè)404錯(cuò)誤,一個(gè)XML文檔,或者一張圖片。

無(wú)論視圖本身包含什么邏輯,都要返回響應(yīng)。代碼寫在哪里也無(wú)所謂,只要它在你當(dāng)前項(xiàng)目目錄下面。除此之外沒(méi)有更多的要求了——可以說(shuō)“沒(méi)有什么神奇的地方”。為了將代碼放在某處,大家約定成俗將視圖放置在項(xiàng)目(project)或應(yīng)用程序(app)目錄中的名為views.py的文件中。

一個(gè)簡(jiǎn)單的視圖

下面是一個(gè)以HTML文檔的形式返回當(dāng)前日期和時(shí)間的視圖:

from django.http import HttpResponse
import datetime

def current_datetime(request):
  now = datetime.datetime.now()
  html = "<html><body>It is now %s.</body></html>" % now
  return HttpResponse(html)

讓我們來(lái)逐行解釋下上面的代碼:

首先,我們從 django.http模塊導(dǎo)入了HttpResponse類,以及Python的datetime庫(kù)。

接著,我們定義了current_datetime函數(shù)。它就是視圖函數(shù)。每個(gè)視圖函數(shù)都使用HttpRequest對(duì)象作為第一個(gè)參數(shù),并且通常稱之為request。

注意,視圖函數(shù)的名稱并不重要;不需要用一個(gè)統(tǒng)一的命名方式來(lái)命名,以便讓Django識(shí)別它。我們將其命名為current_datetime,是因?yàn)檫@個(gè)名稱能夠比較準(zhǔn)確地反映出它實(shí)現(xiàn)的功能。

這個(gè)視圖會(huì)返回一個(gè)HttpResponse對(duì)象,其中包含生成的響應(yīng)。每個(gè)視圖函數(shù)都負(fù)責(zé)返回一個(gè)HttpResponse對(duì)象。

Django使用請(qǐng)求和響應(yīng)對(duì)象來(lái)通過(guò)系統(tǒng)傳遞狀態(tài)。

當(dāng)瀏覽器向服務(wù)端請(qǐng)求一個(gè)頁(yè)面時(shí),Django創(chuàng)建一個(gè)HttpRequest對(duì)象,該對(duì)象包含關(guān)于請(qǐng)求的元數(shù)據(jù)。然后,Django加載相應(yīng)的視圖,將這個(gè)HttpRequest對(duì)象作為第一個(gè)參數(shù)傳遞給視圖函數(shù)。

每個(gè)視圖負(fù)責(zé)返回一個(gè)HttpResponse對(duì)象。視圖層,熟練掌握兩個(gè)對(duì)象即可:請(qǐng)求對(duì)象(request)和響應(yīng)對(duì)象(HttpResponse)

二 CBV和FBV

FBV(function base views) 就是在視圖里使用函數(shù)處理請(qǐng)求。

    之前都是FBV模式寫的代碼,所以就不寫例子了。

CBV(class base views) 就是在視圖里使用類處理請(qǐng)求。

Python是一個(gè)面向?qū)ο蟮木幊陶Z(yǔ)言,如果只用函數(shù)來(lái)開(kāi)發(fā),有很多面向?qū)ο蟮膬?yōu)點(diǎn)就錯(cuò)失了(繼承、封裝、多態(tài))。所以Django在后來(lái)加入了Class-Based-View??梢宰屛覀冇妙悓慥iew。這樣做的優(yōu)點(diǎn)主要下面兩種:

  1. 提高了代碼的復(fù)用性,可以使用面向?qū)ο蟮募夹g(shù),比如Mixin(多繼承)
  2. 可以用不同的函數(shù)針對(duì)不同的HTTP方法處理,而不是通過(guò)很多if判斷,提高代碼可讀性

如果我們要寫一個(gè)處理GET方法的view,用函數(shù)寫的話是下面這樣。

def login(request):
  if request.method == 'GET':
   return render(request, 'login.html')

如果用class-based view寫的話,就是下面這樣:

#類寫法:
class LoginView(View):
  def get(self,request):
   print('get方法執(zhí)行了')
   return render(request,'login2.html')
  def post(self,request):
    username=request.POST.get('username')
    password=request.POST.get('password')
    print('post方法執(zhí)行了')
    print(username,password)
    return HttpResponse('cg')

Django的url是將一個(gè)請(qǐng)求分配給可調(diào)用的函數(shù)的,而不是一個(gè)class。針對(duì)這個(gè)問(wèn)題,class-based view提供了一個(gè)as_view()靜態(tài)方法(也就是類方法),調(diào)用這個(gè)方法,會(huì)創(chuàng)建一個(gè)類的實(shí)例,然后通過(guò)實(shí)例調(diào)用dispatch()方法,dispatch()方法會(huì)根據(jù)request的method的不同調(diào)用相應(yīng)的方法來(lái)處理request(如get(),post()等)。到這里,這些方法和function-based view差不多了,要接收request,得到一個(gè)response返回。如果方法沒(méi)有定義,會(huì)拋出HttpResponseNotAllowed異常。

注意:使用CBV時(shí),urls.py中也做對(duì)應(yīng)的修改::

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

urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r'^login2/$', LoginView.as_view()),

]

CBV傳參,和FBV類似,有名分組,無(wú)名分組

url寫法:無(wú)名分組的

url(r'^cv/(\d{2})/', views.Myd.as_view(),name='cv'),
 url(r'^cv/(?P<n>\d{2})/', views.Myd.as_view(name='xxx'),name='cv'),#如果想給類的name屬性賦值,前提你的Myd類里面必須有name屬性(類屬性,定義init方法來(lái)接受屬性行不通,但是可以自行研究一下,看看如何行通,意義不大),并且之前類里面的name屬性的值會(huì)被覆蓋掉

三 使用Mixin(了解)

我覺(jué)得要理解django的class-based-view(以下簡(jiǎn)稱cbv),首先要明白django引入cbv的目的是什么。在django1.3之前,generic view也就是所謂的通用視圖,使用的是function-based-view(fbv),亦即基于函數(shù)的視圖。有人認(rèn)為fbv比cbv更pythonic,竊以為不然。python的一大重要的特性就是面向?qū)ο?。而cbv更能體現(xiàn)python的面向?qū)ο?。cbv是通過(guò)class的方式來(lái)實(shí)現(xiàn)視圖方法的。class相對(duì)于function,更能利用多態(tài)的特定,因此更容易從宏觀層面上將項(xiàng)目?jī)?nèi)的比較通用的功能抽象出來(lái)。關(guān)于多態(tài),不多解釋,有興趣的同學(xué)自己Google。總之可以理解為一個(gè)東西具有多種形態(tài)(的特性)。cbv的實(shí)現(xiàn)原理通過(guò)看django的源碼就很容易明白,大體就是由url路由到這個(gè)cbv之后,通過(guò)cbv內(nèi)部的dispatch方法進(jìn)行分發(fā),將get請(qǐng)求分發(fā)給cbv.get方法處理,將post請(qǐng)求分發(fā)給cbv.post方法處理,其他方法類似。怎么利用多態(tài)呢?cbv里引入了mixin的概念。Mixin就是寫好了的一些基礎(chǔ)類,然后通過(guò)不同的Mixin組合成為最終想要的類。

所以,理解cbv的基礎(chǔ)是,理解Mixin。Django中使用Mixin來(lái)重用代碼,一個(gè)View Class可以繼承多個(gè)Mixin,但是只能繼承一個(gè)View(包括View的子類),推薦把View寫在最右邊,多個(gè)Mixin寫在左邊。

四 給視圖加裝飾器使用裝飾器裝飾FBV

FBV本身就是一個(gè)函數(shù),所以和給普通的函數(shù)加裝飾器無(wú)差:

from django.shortcuts import render, HttpResponse, redirect
def wrapper(f):
  def innser(*args, **kwargs):
   print('執(zhí)行前')
   ret = f(*args, **kwargs)
   print('執(zhí)行后')
   return ret
  return innser

@wrapper
def index(request):
  print('12321')
  return render(request, 'index.html')

使用裝飾器裝飾CBV

類中的方法與獨(dú)立函數(shù)不完全相同,因此不能直接將函數(shù)裝飾器應(yīng)用于類中的方法 ,我們需要先將其轉(zhuǎn)換為方法裝飾器。

Django中提供了method_decorator裝飾器用于將函數(shù)裝飾器轉(zhuǎn)換為方法裝飾器。

def wrapper(f):
  def innser(*args, **kwargs):
   print('執(zhí)行前')
   ret = f(*args, **kwargs)
   print('執(zhí)行后')
   return ret

  return innser

from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(wrapper,name='get')
class LoginView(View):
  # 使用CBV時(shí)要注意,請(qǐng)求過(guò)來(lái)后會(huì)先執(zhí)行dispatch()這個(gè)方法,如果需要批量對(duì)具體的請(qǐng)求處理方法,如get,post等做一些操作的時(shí)候,這里我們可以手動(dòng)改寫dispatch方法,這個(gè)dispatch方法就和在FBV上加裝飾器的效果一樣。
  # @method_decorator(wrapper)
  def dispatch(self, request, *args, **kwargs):
    # print('之前')
    ret=super().dispatch(request, *args, **kwargs)
    # print('之后')
    return ret

  # @method_decorator(wrapper)
  def get(self,request):
    print('get方法執(zhí)行了')
    return render(request,'login2.html')

  # @method_decorator(wrapper)
  def post(self,request):
    username=request.POST.get('username')
    password=request.POST.get('password')
    print('post方法執(zhí)行了')
    print(username,password)
    return HttpResponse('cg')

另外給cbv添加裝飾器的時(shí)候(先作為了解):

直接添加在dispatch里面,這樣每個(gè)函數(shù)都會(huì)執(zhí)行

from django.utils.decorators import method_decorator

@method_decorator(login_test)
def dispatch(self, request, *args, **kwargs):
res = super(IndexView, self).dispatch(request, *args, **kwargs)
return res

添加在每一個(gè)函數(shù)中

from django.utils.decorators import method_decorator

@method_decorator(login_test)
def get(self, request, *args, **kwargs):
return render(request, 'index.html')

直接添加在類上,后面的name表示只給get添加裝飾器

from django.utils.decorators import method_decorator

@method_decorator(login_test, name='get')

get是給get方法加 (以這種方式如果想給多個(gè)方法加裝飾器,需要寫多層裝飾器,因?yàn)閚ame這個(gè)參數(shù)的值必須是個(gè)字符串,并且不能同時(shí)寫兩個(gè)方法)

@method_decorator(login_test, name='post') post是給post方法加
    class IndexView(View):
    def get(self,request):
      pass

添加裝飾器前必須導(dǎo)入from django.utils.decorators import method_decorator

添加裝飾器的格式必須為@method_decorator(),括號(hào)里面為裝飾器的函數(shù)名

給類添加是必須聲明name

注意csrf-token裝飾器的特殊性,在CBV模式下它只能加在dispatch上面(后面再說(shuō))

  下面這是csrf_token的裝飾器:

  @csrf_protect,為當(dāng)前函數(shù)強(qiáng)制設(shè)置防跨站請(qǐng)求偽造功能,即便settings中沒(méi)有設(shè)置csrfToken全局中間件。

  @csrf_exempt,取消當(dāng)前函數(shù)防跨站請(qǐng)求偽造功能,即便settings中設(shè)置了全局中間件。

  注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect

五 request對(duì)象官方文檔

請(qǐng)求相關(guān)的屬性方法(request--HttpRequest對(duì)象)

def index(request): #http相關(guān)請(qǐng)求信息---封裝--HttpRequest對(duì)象

  if request.method == 'GET':
    print(request.body) #獲取post請(qǐng)求提交過(guò)來(lái)的原始數(shù)據(jù)
    print(request.GET)  #獲取GET請(qǐng)求提交的數(shù)據(jù)
    # print(request.META) # 請(qǐng)求頭相關(guān)信息,就是一個(gè)大字典
    print(request.path) #/index/ 路徑
    print(request.path_info) #/index/ 路徑
    print(request.get_full_path()) #/index/?username=dazhuang&password=123
    
    return render(request,'index.html')
  else:
    print(request.body) # b'username=dazhuang'
    print(request.POST) #獲取POST請(qǐng)求提交的數(shù)據(jù)
    return HttpResponse('男賓三位,拿好手牌!')

六 response對(duì)象

與由Django自動(dòng)創(chuàng)建的HttpRequest對(duì)象相比,HttpResponse對(duì)象是我們的職責(zé)范圍了。我們寫的每個(gè)視圖都需要實(shí)例化,填充和返回一個(gè)HttpResponse。

HttpResponse類位于django.http模塊中。

HttpResponse --- 回復(fù)字符串的時(shí)候來(lái)使用
render --- 回復(fù)一個(gè)html頁(yè)面的時(shí)候使用
redirect -- 重定向
  示例:
  def login(request):
    if request.method == 'GET':
      return render(request,'login.html')
    else:
      username = request.POST.get('username')
      password = request.POST.get('password')
      if username == 'taibai' and password == 'dsb':
        # return render(request,'home.html')
        return redirect('/home/') #重定向
      else:
        return HttpResponse('滾犢子,趕緊去充錢!!!')

  #首頁(yè)
  def home(request):
    return render(request,'home.html')
  
  
HttpResponse.content:響應(yīng)內(nèi)容
HttpResponse.charset:響應(yīng)內(nèi)容的編碼
HttpResponse.status_code:響應(yīng)的狀態(tài)碼

redirect() :給瀏覽器了一個(gè)30x的狀態(tài)碼

  參數(shù)可以是:

一個(gè)模型:將調(diào)用模型的get_absolute_url() 函數(shù)

   2.一個(gè)視圖,可以帶有參數(shù):將使用urlresolvers.reverse 來(lái)反向解析名稱

   3.一個(gè)絕對(duì)的或相對(duì)的URL,將原封不動(dòng)的作為重定向的位置。

   默認(rèn)返回一個(gè)臨時(shí)的重定向;傳遞permanent=True 可以返回一個(gè)永久的重定向。

   示例:

​ 你可以用多種方式使用redirect() 函數(shù)。

def login(request):
  if request.method == 'GET':
   return render(request, 'login.html')
  else:
   username = request.POST.get('username')
   password = request.POST.get('password')
   if username == 'anwen@123' and password == '123':
     return redirect('/app01/home/') ##重定向到/app01/home/路徑,這也是發(fā)送了一個(gè)請(qǐng)求,別忘了在上面引入這個(gè)redirect類,和render、Httpresponse在一個(gè)地方引入
   else:
     return HttpResponse('登錄失??!')


def home(request):
  return render(request, 'home.html')
#app01里的 urls.py
from django.conf.urls import url
from app01 import views
urlpatterns=[
  url(r'^$',views.login),
  url(r'^home/',views.home),
]

上面幾個(gè)文件搞好之后,我們重啟Django項(xiàng)目,然后登陸頁(yè)面的輸入網(wǎng)址,注意,你輸入的網(wǎng)址端口要和你啟動(dòng)的django項(xiàng)目的端口一樣。

Django基礎(chǔ)三之視圖函數(shù)的使用方法

| 一點(diǎn)擊提交按鈕,你看一下network里面發(fā)送了幾個(gè)請(qǐng)求:兩個(gè)請(qǐng)求,一個(gè)是login請(qǐng)求,一個(gè)index請(qǐng)求。 |

Django基礎(chǔ)三之視圖函數(shù)的使用方法

擴(kuò)展閱讀:** key兩次請(qǐng)求,關(guān)于301和302:   

1)301和302的區(qū)別。

301和302狀態(tài)碼都表示重定向,就是說(shuō)瀏覽器在拿到服務(wù)器返回的這個(gè)狀態(tài)碼后會(huì)自動(dòng)跳轉(zhuǎn)到一個(gè)新的URL地址,這個(gè)地址可以從響應(yīng)的Location首部中獲取
(用戶看到的效果就是他輸入的地址A瞬間變成了另一個(gè)地址B)——這是它們的共同點(diǎn)。

他們的不同在于。301表示舊地址A的資源已經(jīng)被永久地移除了(這個(gè)資源不可訪問(wèn)了),搜索引擎在抓取新內(nèi)容的同時(shí)也將舊的網(wǎng)址交換為重定向之后的網(wǎng)址;

302表示舊地址A的資源還在(仍然可以訪問(wèn)),這個(gè)重定向只是臨時(shí)地從舊地址A跳轉(zhuǎn)到地址B,搜索引擎會(huì)抓取新的內(nèi)容而保存舊的網(wǎng)址。 SEO302好于301

2)重定向原因:

(1)網(wǎng)站調(diào)整(如改變網(wǎng)頁(yè)目錄結(jié)構(gòu));
(2)網(wǎng)頁(yè)被移到一個(gè)新地址;
(3)網(wǎng)頁(yè)擴(kuò)展名改變(如應(yīng)用需要把.php改成.Html或.shtml)。

這種情況下,如果不做重定向,則用戶收藏夾或搜索引擎數(shù)據(jù)庫(kù)中舊地址只能讓訪問(wèn)客戶得到一個(gè)404頁(yè)面錯(cuò)誤信息,訪問(wèn)流量白白喪失;再者某些注冊(cè)了多個(gè)域名的網(wǎng)站,也需要通過(guò)重定向讓訪問(wèn)這些域名的用戶自動(dòng)跳轉(zhuǎn)到主站點(diǎn)等。

臨時(shí)重定向(響應(yīng)狀態(tài)碼:302)和永久重定向(響應(yīng)狀態(tài)碼:301)對(duì)普通用戶來(lái)說(shuō)是沒(méi)什么區(qū)別的,它主要面向的是搜索引擎的機(jī)器人。

  1. A頁(yè)面臨時(shí)重定向到B頁(yè)面,那搜索引擎收錄的就是A頁(yè)面。
  2. A頁(yè)面永久重定向到B頁(yè)面,那搜索引擎收錄的就是B頁(yè)面。
  3. 用redirect可以解釋APPEND_SLASH的用法!

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI