1. 程式人生 > 資訊 >俄烏局勢推高鎳鋁價格:電動汽車電池關鍵材料價格創新高

俄烏局勢推高鎳鋁價格:電動汽車電池關鍵材料價格創新高

內容概要

  • request 物件方法
  • FBV 與 CBV
  • CBV 原始碼刨析
  • 三板斧介紹
  • JsonResponse 物件
  • 檔案上傳

內容詳細

request 物件方法

參考官方文件: https://docs.djangoproject.com/en/1.11/ref/request-response/

當瀏覽器向服務端請求一個頁面時,Django會建立一個HttpRequest物件,該物件包含關於請求的原資料,然後再通過路由配置呼叫相應的檢視函式,並把HttpResponse物件當作引數傳給檢視函式,約定俗成檢視函式用 request 來接收 HttpResponse 物件,此時 HttpResponse 物件也成為 request 物件

檢視函式執行完畢之後,需要有一個返回值,也是返回一個 HttpResponse 物件。

檢視函式:

def test1(request):
    return HttpResponse('app01 test1')

def index(request):
    return render(request, 'index.html')

def beauty(request):
    return redirect('https://www.mmzztt.com')

注意: django 三板斧 render, HttpResponse, redirect,通過原始碼也可以知道 render,redirect 最終也是返回一個 HttpResponse 物件。

request 物件常用的方法以及作用

def test(request):
    if request.method == 'POST':
        print(request.POST)
    if request.method == 'GET':
        print(request.GET)
    return HttpResponse('ok')
  • method 請求中使用的HTTP方法的字串表示,全大寫表示。

包含 GET、POST、等提交方式字串

  • GET 包含所有HTTP GET引數的類字典物件

接收GET請求資料,一般為urlencode型別的資料,也可以接收url問號後面傳輸過來的資料

  • POST 包含所有HTTP POST引數的類字典物件

當form表單新增method="post",資料提交方式變成了POST請求

  • FILES 包含所有上傳的檔案資訊

注意!form表單提交資料前需要新增屬性 enctype="multipart/form-data" ,在後端 request.FILES 才能拿到檔案資料

  • body 請求體,byte型別 request.POST的資料就是從body裡面提取到的

一個字串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,例如:二進位制圖、XML,Json等。可以用 request.body 來獲取前端傳過來的 Json 資料型別

  • path_info 返回使用者訪問url,不包括域名
  • get_full_path_info() 返回使用者訪問的url地址(路徑),還可以拿到問號後面的鍵值
"/music/bands/the_beatles/?print=true"

FBV 與 CBV

FBV (function base views)

顧名思義基於函式的檢視類

我們之前寫過的都是基於函式的view,就叫FBV

def login(request):
    request.get_full_path_info()
    if request.method == "POST":
        print(request.POST)
        print(request.FILES)
    return render(request, 'login.html')

路由與檢視函式對應關係:

urlpatterns = [
    path('login/', views.login),
]
  • 給 FBV 新增裝飾器

直接正常在函式頭上新增語法糖即可

@login_auth
def login(request):
    if request.method == "POST":
        print(request.POST)
        print(request.FILES)
    return render(request, 'login.html')

CBV (class base views)

基於類的檢視類

用類來寫檢視函式,類中定義相應的請求方式函式,GET請求來了就去get的檢視函式,POST請求來了就去get的檢視函式

class MyClass(View):
    def get(self, request):
        return HttpResponse('get 請求')

    def post(self, request):
        return HttpResponse('post 請求')

路由與檢視函式對應關係:

urlpatterns = [
    path('CBV/', views.MyClass.as_view()),
]

# 記住: as_view() 要加括號呼叫,返回的是view
  • 給 CBV 新增裝飾器

類中的方法與獨立函式不完全相同,因此不能直接將函式裝飾器應用於類中的方法 ,我們需要先將其轉換為方法裝飾器。

Django中提供了method_decorator裝飾器用於將函式裝飾器轉換為方法裝飾器。需要匯入 django.utils.decorators 裝飾器模組 的 method_decorator 函式

給 CBV 新增方法裝飾器的三種方式:

# 簡易裝飾器
def login_auth(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        return res

    return inner

1、在類中函式頭上新增(不推薦使用)

from django.utils.decorators import method_decorator

class MyClass(View):
    @method_decorator(login_auth)
    def get(self, request):
        return HttpResponse('get 請求')

    @method_decorator(login_auth)
    def post(self, request):
        return HttpResponse('post 請求')

2、在類頭上新增

這種方法還可以指定給不同的方法新增不同的裝飾器

@method_decorator(login_auth, name='get')
@method_decorator(login_auth, name='post')
class MyClass(View):
    def get(self, request):
        return HttpResponse('get 請求')

    def post(self, request):
        return HttpResponse('post 請求')

3、根據原始碼,在 dispatch 函式上新增裝飾器,既可以做到作用於所有類方法

class MyClass(View):
    @method_decorator(login_auth)
    def dispatch(self, request, *args, **kwargs):
        pass

    def get(self, request):
        return HttpResponse('get 請求')

    def post(self, request):
        return HttpResponse('post 請求')

CBV 原始碼刨析

從路由檔案 urls.py 的呼叫語句中看起

urlpatterns = [
    path('CBV/', views.MyClass.as_view()),
]
# as_view() 函式加括號優先呼叫 as_view函式

按住 ctrl 鍵,滑鼠點選檢視 as_view 原始碼

@classonlymethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)		# self 是我們自定義類產生的物件
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):	# 自定義類必須接收 request 物件,否則主動報錯
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
         return self.dispatch(request, *args, **kwargs)		# view 函式呼叫 View 類中的dispath函式
    # ... 中間省略部分原始碼
    return view		# 返回view函式物件

從原始碼中可以看出,as_view 呼叫之後得到的是 view 函式物件,這是個閉包函式,當檢視函式被觸發,呼叫的是 view函式,view函式return一個 dispatch 函式呼叫結果

我們再檢視 dispatch 的原始碼:

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn't exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn't on the approved list.
    if request.method.lower() in self.http_method_names:	# 如果是request中的屬性,則用反射呼叫自身的響應的函式
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

三板斧介紹

三板斧官方文件: https://docs.djangoproject.com/en/1.11/topics/http/shortcuts/

render

結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 物件。

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

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

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

     content_type:生成的文件要使用的MIME型別。預設為 DEFAULT_CONTENT_TYPE 設定的值。預設為'text/html'

     status:響應的狀態碼。預設為200。   useing: 用於載入模板的模板引擎的名稱。一個簡單的例子:
from django.shortcuts import render

def my_view(request):
    # 檢視的程式碼寫在這裡
    return render(request, 'myapp/index.html', {'foo': 'bar'})

上面的程式碼等於

from django.http import HttpResponse
from django.template import loader

def my_view(request):
    # 檢視程式碼寫在這裡
    t = loader.get_template('myapp/index.html')
    c = {'foo': 'bar'}
    return HttpResponse(t.render(c, request))

redirect

引數可以是:

  • 一個模型:將呼叫模型的get_absolute_url() 函式
  • 一個檢視,可以帶有引數:將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的作為重定向的位置。

預設返回一個臨時的重定向;傳遞permanent=True 可以返回一個永久的重定向。

示例:

你可以用多種方式使用redirect() 函式。

傳遞一個具體的ORM物件(瞭解即可)

將呼叫具體ORM物件的get_absolute_url() 方法來獲取重定向的URL:

from django.shortcuts import redirect
 
def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object)

傳遞一個檢視的名稱

def my_view(request):
    ...
    return redirect('some-view-name', foo='bar')

傳遞要重定向到的一個具體的網址

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

當然也可以是一個完整的網址

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

預設情況下,redirect() 返回一個臨時重定向。以上所有的形式都接收一個permanent 引數;如果設定為True,將返回一個永久的重定向:

def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)  

擴充套件閱讀:

臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通使用者來說是沒什麼區別的,它主要面向的是搜尋引擎的機器人。

A頁面臨時重定向到B頁面,那搜尋引擎收錄的就是A頁面。

A頁面永久重定向到B頁面,那搜尋引擎收錄的就是B頁面。

HttpResponse

JsonResponse 物件

json 格式資料的作用:

前後端在進行跨語言資料互動時,需要傳輸字典等更多特殊資料型別,而不是僅僅只有字串

json格式的資料在經過序列化和反序列化,可以實現多種資料型別跨語言傳輸,所以幾乎每種語言都會有專門序列化和反序列化json格式資料的方法

# pyhton
import json
data = {'name': 'elijah', 'age': 18}
res = json.dumps(data, ensure_ascii=False)		# ensure_ascii=False 取消中文轉二進位制
json.loads(res)		# 反序列化
// javascript
data = {'name': 'elijah', 'age': 18}
res = json.stringfy(data)		// 序列化
json.parse(res)			// 反序列化

檢視函式中使用 JsonResponse 方法可以直接把字典轉為json資料並傳給前端

首先得匯入 JsonResponse 類

from django.http import JsonResponse

def my_json(request):
    data = {'name': 'elijah', 'age': 18}
    return JsonResponse(data)

這是 JsonResponse 的原始碼:

  • safe

safe 值為 True 表示JsonResponse 只能接收字典型別,為 False 則表示可以接收列表等其它資料型別

  • json_dumps_params

由原始碼可知,json_dumps_params 引數最後時一個字典, ** 符號的作用就是把字典中的鍵值對打散變為關鍵字引數傳給 json.dump() 函式

所以如果不想中文被轉為二進位制,則需要給json_dumps_params賦值一個字典,值為 {'ensure_ascii': 'False'}

def my_json(request):
    data = {'name': 'elijah', 'age': 18}
    return JsonResponse(data, json_dumps_params={'ensure_ascii': False}, safe=False)

檔案上傳

前端:

前端給後端傳輸檔案資料,則需要給form表單標籤新增屬性 enctype="multipart/form-data"

這樣,前端的資料會以 formdata 的資料格式傳給後端

前端常見傳輸的資料格式:

  • urlencode: name=elijah&age=18

  • formdata:可以傳輸檔案資料

  • json:跨語言傳輸資料格式

<form action="" method="post" enctype="multipart/form-data">
    <label for="username">username:</label>
    <input type="text" class="form-control" id="username" name="username">
    <div class="form-group">
        <label for="f1">頭像:
            <img src="" alt="">
        </label>
        <input type="file" name="file" id="f1">
    </div>
    <input type="button" id="ajax_btn">
    <input type="submit" class="btn btn-primary btn-lg pull-left">
</form>

ajax 傳輸檔案資料:

如果是以 ajax 的方式傳輸檔案資料,則需要使用 javascript 的 formdata 物件,並且傳輸資料時,需要告訴瀏覽器不要對formdata物件進行修改

<script>
    $('#ajax_btn').on('click', function () {
        // 例項化FormData物件
        let formDataObj = new FormData()
        // 新增普通資料
        formDataObj.append('username', 'elijah')
        // 新增檔案資料
        formDataObj.append('file', $('#f1')[0].file[0])
        // ajax
        $.ajax({
            url:"",
            type: 'post',
            data: formDataObj,

            // 提示瀏覽器不要修改傳輸的資料,和不定義資料型別
            processData:false,
            contentType:false,

            success:function (arg){
                console.log(arg)
            }
        })
    })
</script>

後端:

後端用 request.FILES 方法接收檔案資料(是個字典),再用.get() 方法獲取檔案物件,並儲存到目錄中,檔案路徑儲存在表的檔案欄位中。

def login(request):
    request.get_full_path_info()
    if request.method == "POST":
        print(request.POST)
        print(request.FILES)
        files_obj = request.FILES.get('file')   # 獲取的是檔案物件
        print(files_obj.name)   # 獲取檔名字
        with open(files_obj.name, 'wb') as f:
            for line in files_obj:      # 檔案物件可以迴圈讀取並寫入
                f.write(line)
    return render(request, 'login.html')

列印結果: