俄烏局勢推高鎳鋁價格:電動汽車電池關鍵材料價格創新高
內容概要
- 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')
列印結果: