1. 程式人生 > 其它 >Django檢視層及其他補充

Django檢視層及其他補充

目錄

Django檢視層及其他補充

一 Django之檢視層

1 檢視層之請求物件

1.1 request屬性

	django將請求報文中的請求行、首部資訊、內容主體封裝成 HttpRequest 類中的屬性。 除了特殊說明的之外,其他均為只讀的。
1).HttpRequest.GET

  一個類似於字典的物件,包含 HTTP GET 的所有引數。詳情請參考 QueryDict 物件。

2).HttpRequest.POST

  一個類似於字典的物件,如果請求中包含表單資料,則將這些資料封裝成 QueryDict 物件。

  POST 請求可以帶有空的 POST 字典 —— 如果通過 HTTP POST 方法傳送一個表單,但是表單中沒有任何的資料,QueryDict 物件依然會被建立。
   因此,不應該使用 if request.POST  來檢查使用的是否是POST 方法;應該使用 if request.method == "POST"
  另外:如果使用 POST 上傳檔案的話,檔案資訊將包含在 FILES 屬性中。
   
   注意:鍵值對的值是多個的時候,比如checkbox型別的input標籤,select標籤,需要用:
        request.POST.getlist("hobby")

3).HttpRequest.body

  一個字串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,例如:二進位制圖片、XML,Json等。
  但是,如果要處理表單資料的時候,推薦還是使用 HttpRequest.POST 。


4).HttpRequest.path

  一個字串,表示請求的路徑元件(不含域名)。
  例如:"/music/bands/the_beatles/"

5).HttpRequest.method

  一個字串,表示請求使用的HTTP 方法。必須使用大寫。
  例如:"GET"、"POST"

6).HttpRequest.encoding

  一個字串,表示提交的資料的編碼方式(如果為 None 則表示使用 DEFAULT_CHARSET 的設定,預設為 'utf-8')。
   這個屬性是可寫的,你可以修改它來修改訪問表單資料使用的編碼。
   接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取資料)將使用新的 encoding 值。
   如果你知道表單資料的編碼不是 DEFAULT_CHARSET ,則使用它。

7).HttpRequest.META 【重點】

   一個標準的Python 字典,包含所有的HTTP 首部。具體的頭部資訊取決於客戶端和伺服器,下面是一些示例:  取值:

    CONTENT_LENGTH —— 請求的正文的長度(是一個字串)。
    CONTENT_TYPE —— 請求的正文的MIME 型別。
    HTTP_ACCEPT —— 響應可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
    HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
    HTTP_HOST —— 客服端傳送的HTTP Host 頭部。
    HTTP_REFERER —— Referring 頁面。
    HTTP_USER_AGENT —— 客戶端的user-agent 字串。
    QUERY_STRING —— 單個字串形式的查詢字串(未解析過的形式)。
    REMOTE_ADDR —— 客戶端的IP 地址。
    REMOTE_HOST —— 客戶端的主機名。
    REMOTE_USER —— 伺服器認證後的使用者。
    REQUEST_METHOD —— 一個字串,例如"GET" 或"POST"。
    SERVER_NAME —— 伺服器的主機名。
    SERVER_PORT —— 伺服器的埠(是一個字串)。
   從上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,請求中的任何 HTTP 首部轉換為 META 的鍵時,
    都會將所有字母大寫並將連線符替換為下劃線最後加上 HTTP_  字首。
    所以,一個叫做 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。

8).HttpRequest.FILES

  一個類似於字典的物件,包含所有的上傳檔案資訊。
   FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的資料。
  注意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會
   包含資料。否則,FILES 將為一個空的類似於字典的物件。


9).HttpRequest.COOKIES

  一個標準的Python 字典,包含所有的cookie。鍵和值都為字串。

10).HttpRequest.session

   一個既可讀又可寫的類似於字典的物件,表示當前的會話。只有當Django 啟用會話的支援時才可用。
    完整的細節參見會話的文件。

11).HttpRequest.user(使用者認證元件下使用)

  一個 AUTH_USER_MODEL 型別的物件,表示當前登入的使用者。

  如果使用者當前沒有登入,user 將設定為 django.contrib.auth.models.AnonymousUser 的一個例項。你可以通過 is_authenticated() 區分它們。

    # 例如:

    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.

	user 只有當Django 啟用 AuthenticationMiddleware 中介軟體時才可用。

     -------------------------------------------------------------------------------------

    # 匿名使用者
    class models.AnonymousUser

    django.contrib.auth.models.AnonymousUser 類實現了django.contrib.auth.models.User 介面,但具有下面幾個不同點:

    id 							# 永遠為None。
    username 					# 永遠為空字串。
    get_username() 				# 永遠返回空字串。
    is_staff 和 is_superuser 	# 永遠為False。
    is_active 					# 永遠為 False。
    groups 和 user_permissions 	# 永遠為空。
    is_anonymous() 				# 返回True 而不是False。
    is_authenticated() 			# 返回False 而不是True。
    set_password()、check_password()、save() 和delete() 	# 引發 NotImplementedError。
    New in Django 1.8:
    新增 AnonymousUser.get_username() 	# 以更好地模擬 django.contrib.auth.models.User。

1.2 request常用方法

1).HttpRequest.get_full_path()

  返回 path,如果可以將加上查詢字串。

  例如:"/music/bands/the_beatles/?print=true"
  注意和path的區別:http://127.0.0.1:8001/order/?name=lqz&age=10

2).HttpRequest.is_ajax()

  如果請求是通過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是否是字串'XMLHttpRequest'。

  大部分現代的 JavaScript 庫都會發送這個頭部。如果你編寫自己的 XMLHttpRequest 呼叫(在瀏覽器端),你必須手工設定這個值來讓 is_ajax() 可以工作。

  如果一個響應需要根據請求是否是通過AJAX 發起的,並且你正在使用某種形式的快取例如Django 的 cache middleware,
   你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的檢視以讓響應能夠正確地快取。

1.3 其他程式碼示例:

def index(request):
    '''
    request:django封裝的物件,它的類是WSGIRequest,它裡面包含了所有http請求的東西
    '''
    print(request)
    print(type(request))
    # from django.core.handlers.wsgi import WSGIRequest
    #######################1 講過的
    print(request.method)
    print(request.GET)
    print(request.POST)

    ########################2 新講的path,get_full_path,META,FIELS,body
    # 自定製請求頭
    # 上傳檔案使用的編碼方式是form-data,預設編碼方式urlencoded
    print(request.is_ajax()) # 是不是ajax請求
    print(request.path)      # 請求路徑
    print(request.get_full_path()) # 請求全路徑,帶資料

    # print(request.body)      # 請求體,二進位制,如果傳檔案,這個報錯
    '''
    使用form表單,預設情況下資料被轉成name=lqz&password=123放到請求體中
    request.POST其實是從body中取出bytes格式的,轉成了字典
    requet.GET其實是把路徑中?後面的部分拆出來,轉成了字典
    '''
    print(request.encoding) # 客戶端向服務端傳遞時,使用的編碼方法

    print(request.META)    # 重點,字典,一堆東西,請求使用者的ip地址,請求頭中資料,使用者自定製請求頭的資料
    '''
    把請求頭的key值部分統一加HTTP_  並且全部轉成大寫
    '''
    print(request.META['REMOTE_ADDR'])  # 客戶端的ip地址
    print(request.FILES)  # 客戶端上傳的檔案

    ########################3 暫時不用關注(後面會講)
    print(request.COOKIES) # 空字典
    print(request.session) # session物件
    print(request.user)    # 匿名使用者
    return HttpResponse('ok')

2 檢視層之響應物件及JsonResponse

# 響應物件主要有三種形式
    -- HttpResponse()
    -- render()
    -- redirect()
# HttpResponse()括號內直接跟一個具體的字串作為響應體,比較直接很簡單,所以這裡主要介紹後面兩種形式。

2.1 render( )

render(request, template_name[, context])
 
# 結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 物件。

引數:
     request: 用於生成響應的請求物件。

     template_name:要使用的模板的完整名稱,可選的引數

     context:新增到模板上下文的一個字典。預設是一個空字典。如果字典中的某個值是可呼叫的,檢視將在渲染模板之前呼叫它。

# render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面作為響應體。

2.2 redirect( )

# 一、 用途:
1).傳遞要重定向的一個硬編碼的URL

def my_view(request):
    ...
    return redirect('/some/url/')

2).也可以是一個完整的URL:

def my_view(request):
    ...
    return redirect('http://www.baidu.com/') 

# 二、關於重定向的補充
1)301和302的區別。

  301和302狀態碼都表示重定向,就是說瀏覽器在拿到伺服器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址可以從響應的Location首部中獲取(使用者看到的效果就是他輸入的地址A瞬間變成了另一個地址B)——這是它們的共同點。
    他們的不同在於。【1】301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜尋引擎在抓取新內容的同時也將舊的網址交換為重定向之後的網址;
	【2】302表示舊地址A的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜尋引擎會抓取新的內容而儲存舊的網址。 SEO302好於301
 

2)重定向原因:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁副檔名改變(如應用需要把.php改成.Html或.shtml)。
	這種情況下,如果不做重定向,則使用者收藏夾或搜尋引擎資料庫中舊地址只能讓訪問客戶得到一個404頁面錯誤資訊,訪問流量白白喪失;再者某些註冊了多個域名的網站,也需要通過重定向讓訪問這些域名的使用者自動跳轉到主站點等。

2.3 JsonResponse

# 向前端返回一個json格式字串的兩種方式

# 第一種方式
import json
# data={'name':'lqz','age':18}
data1=['lqz','egon']
return HttpResponse(json.dumps(data1))


# 第二種方式
from django.http import JsonResponse
# data = {'name': 'lqz', 'age': 18}
data1 = ['lqz', 'egon']
# return JsonResponse(data)
return JsonResponse(data1,safe=False,json_dumps_params={'ensure_ascii':False})  # 轉換除字典以外的格式資料,需設定【safe=False】屬性;;若資料中含有中文,則需要以【字典】的形式設定【json_dumps_params={'ensure_ascii':False}】屬性。

2.4 其他程式碼示例:

### 重點:JsonResponse的使用(看原始碼)

def index(request):
    # 三件套
    # return HttpResponse('ok')
    # return render(request,'index.html',context={'name':'lqz','age':18})
    # return redirect('/home') # 重定向自己的地址,重定向第三方地址,經常跟反向解析一起使用

    # 向客戶端返回json格式資料
    # import json
    # res=json.dumps({'name':'劉清政','age':18},ensure_ascii=False)
    # return HttpResponse(res)
    # django內建提供的JsonResponse
    # 本質還是HttpResponse

    # ensure_ascii
    # return JsonResponse({'name':'劉清政','age':18},json_dumps_params={'ensure_ascii':False})
    # safe,轉換除字典以外的格式,需要safe=False
    return JsonResponse([11,12,13,'lqz',[1,2,3],{'name':'lqz','age':19}],safe=False)

3 cbv和fbv

# CBV基於類的檢視(Class base view)和FBV基於函式的檢視(Function base view)

# 寫檢視類(還是寫在views.py中)
## 第一步,寫一個類,繼承View
from django.views import View

class Index(View):
    def dispatch(self, request, *args, **kwargs):
        print(request)
        print(args)
        print(kwargs)
        # 可以寫類似裝飾器的東西,在前後加程式碼
        obj=super().dispatch(request, *args, **kwargs)
        return obj
    
    def get(self, request):  # 當url匹配成功,get請求,會執行它
        return HttpResponse('ok')

    def post(self,request):
        return HttpResponse('post')
    
## 第二步:配置路由
path('index/', views.Index.as_view()),

# 先FBV,後,drf全是CBV

4 cvb本質(重點)

4.1 pycharm檢視原始碼設定

4.2 cbv本質

#  cbv本質

# 1 請求來了,路由匹配成功執行 path('index/', views.Index.as_view()),
	執行views.Index.as_view()()
# 2 本質是執行as_view()內部有個閉包函式view()
# 3 本質是view()---》dispatch()
# 4 dispatch內部,根據請求的方法(get,post)---->執行檢視類中的def get  def post

5 檔案上傳

## html注意編碼方式
<form action="/index/" method="post" enctype="multipart/form-data">

    <p>使用者名稱:<input type="text" name="name"></p>
    <p>密碼:<input type="password" name="password"></p>
    <p><input type="file" name="myfile"></p>
    <p><input type="submit" value="提交"></p>
</form>

# views.py
def index(request):
    file=request.FILES.get('myfile')
    # 開啟一個空檔案,寫入
    with open(file.name,'wb') as f:
        for line in file.chunks():
            f.write(line)
    return HttpResponse('檔案上傳成功')

6 前後端互動編碼方式

1) urlencoded---->傳普通的資料,form表單預設就是這種---->request.POST
2) form-data----->傳檔案和資料                   ---->request.POST   request.FILES
3) json---------->傳json格式資料                 ---->request.body中取出來自行處理

def index(request):
    # 接收urlencoded編碼
    body體中資料格式:name=lqz&age=18
    # print(request.POST)

    # 接收form-data編碼
    body體中:分兩部分,一部分是資料,一部分是檔案
    資料部分格式:name=lqz&age=18
    ---asdfasdfasdfgasgasgd---
    檔案部分(二進位制)
    
    #資料部分
    # print(request.POST)
    # #檔案部分
    # print(request.FILES)

    # 接收json格式
    body體中 
    {
    "name": "lqz",
    "age": 18
	}
    # 這裡沒有
    print(request.POST)
    # 資料在這(自行處理)
    print(request.body)

    return HttpResponse('ok')

二 其他補充

1 postman軟體

模擬傳送http請求(控制請求路徑,請求方式,請求頭,請求體)

2 form表單,提交地址

# action
#1 不寫,預設向當前地址傳送請求
#2 /index/,向當前域(http://127.0.0.1:8000/)的/index/傳送請求
#3 http://127.0.0.1:8000/index/,向該地址傳送請求(可以向第三方服務傳送請求)

# method
# 1 post:傳送post請求(預設編碼情況下:以key=value&key=value的形式拼到請求體中)
# 2 get:傳送get請求(以key=value&key=value的形式拼到路徑中)
<form action="/index/" method="post">

    <p>使用者名稱:<input type="text" name="name"></p>
    <p>密碼:<input type="text" name="password"></p>
    <p><input type="submit" value="提交"></p>
</form>

3 Pycharm的自動提示

from django.core.handlers.wsgi import WSGIRequest
# pycharm的自動提示
request=request  # type: WSGIRequest