一個檢視函數,簡稱檢視,是一個簡單的 Python 函數,它接受 Web 請求並且返回 Web 響應。
響應可以是一個 HTML 頁面、一個 404 錯誤頁面、重定向頁面、XML 檔案、或者一張圖片…
每個檢視函數都負責返回一個 HttpResponse 物件,物件中包含生成的響應。
程式碼寫在哪裡都可以,只要在 Python 目錄下面,一般約定是將檢視放置在專案或應用程式目錄中的名為views.py的檔案中。
檢視層,熟練掌握兩個物件即可:請求物件(request)和響應物件(HttpResponse)
django檢視函數必須要返回一個HttpResponse物件
否則報錯:The view app01.views.func1 didn't return an HttpResponse object. It returned None instead.提示你沒有返回一個Httpresponse物件而是返回了一個None。
為什麼必須要返回這個物件呢?我們 Ctrl + 滑鼠點選分別檢視三者的原始碼來查探究竟。
class HttpResponse(HttpResponseBase): """ An HTTP response class with a string as content. This content that can be read, appended to or replaced. """ streaming = False def __init__(self, content=b'', *args, **kwargs): super(HttpResponse, self).__init__(*args, **kwargs) # Content is a bytestring. See the `content` property methods. self.content = content
由此可得,HttpResponse()就是物件,括號內直接跟一個具體的字串作為響應體,範例如下
HttpResponse(): 返回文字,引數為字串,字串中寫文字內容。如果引數為字串裡含有 html 標籤,也可以渲染。 def runoob(request): # return HttpResponse("百度首頁") return HttpResponse("<a href='https://www.baidu.com/'>百度首頁</a>")
def render(request, template_name, context=None, content_type=None, status=None, using=None): """ Returns a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ content = loader.render_to_string(template_name, context, request, using=using) return HttpResponse(content, content_type, status) ''' render(request, template_name[, context])` `結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 物件。 引數: request: 用於生成響應的請求物件。 template_name:要使用的模板的完整名稱,可選的引數 context:新增到模板上下文的一個字典。預設是一個空字典。如果字典中的某個值是可呼叫的,檢視將在渲染模板之前呼叫它。 render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面作為響應體。 '''
響應物件
全稱:JSON的全稱是"JavaScript Object Notation", 意思是JavaScript物件表示法
作用:前後端互動一般使用的是json實現資料的跨域傳輸
方法一:直接自己序列化
import json def index_func(request): user_dict = {'name':'alex','age':'18','性別':'女'} user_json = json.dumps(user_dict,ensure_ascii=False) return HttpResponse(user_json) # 新增ensure_ascii=False 引數是為了讓中文保持正常顯示, 不然會轉換成uncode格式
方法二:使用JsonResponse物件
from django.http import JsonResponse def index_func(request): user_dict = {'name':'alex','age':'18','性別':'女'} return JsonResponse(user_dict)
問題:bJsonResponse 物件沒有 ensure_ascii
引數來保證中文正常顯示嗎?
首先,我們來檢視原始碼。
由原始碼可知,json_dumps_params
是一個字典,接下來我們為json_dumps_params
傳入引數。
from django.http import JsonResponse def index_func(request): user_dict = {'name':'alex','age':'18','性別':'女'} return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
ps:以後寫程式碼很多時候可能需要參考原始碼及所學知識擴充套件功能
class JsonResponse(): def __init__(self,data,json_dumps_params=None): json.dumps(data,**json_dumps_params)
JsonResponse主要序列化字典,針對非字典的其他可以被序列化的資料需要修改safe引數為False
from django.http import JsonResponse def index_func(request): user_list = [11,22,33,44,55] return JsonResponse(user_list,json_dumps_params={'ensure_ascii':False})
提示為了讓非字典物件能夠被序列化,設定safe引數為false。
我程式碼沒有寫這個啊,這是哪來的呢?
憑空捏造??且看JsonResonse
原始碼
加入 safe=False
引數, 讓其允許非 dict 物件被序列化
from django.http import JsonResponse def index_func(request): user_list = [11,22,33,44,55] return JsonResponse(user_list,safe=False,json_dumps_params={'ensure_ascii':False})
ps:JsonResponse
返回的也是HttpResponse
物件
class JsonResponse(HttpResponse): # 繼承了HttpResponse ...
request.FILES # 獲取檔案物件
method
必須是post
enctype
引數修改為multipart/form-data
index_Page.html檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <p>file: <input type="file" name="file" multiple="multiple"> </p> <input type="submit" value="提交"> </form> </body> </html>
views.py檔案
from django.shortcuts import render def index_func(request): if request.method == 'POST': # 獲取檔案資料 print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 試卷.pdf (application/pdf)>]}> # 獲取檔案資料物件 file_obj = request.FILES.get('file') print(file_obj,type(file_obj)) # 試卷.pdf <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> # 獲取檔案物件字串名 print(file_obj.name,type(file_obj.name)) # 試卷.pdf <class 'str'> with open(r'%s' % file_obj.name, 'wb') as f: for line in file_obj: f.write(line) return render(request,'indexPage.html')
基於檢視的函數我們學習Django的時候就就已經在使用了,範例如下:
urls.py檔案
urlpatterns = [ path("login/", views.login), ]
views.py檔案
from django.shortcuts import render,HttpResponse def login(request): if request.method == "GET": return HttpResponse("GET 方法") if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") if user == "shawn" and pwd == "123456": return HttpResponse("POST 方法") else: return HttpResponse("POST 方法1")
如果我們在瀏覽器中直接存取 http://127.0.0.1:8000/login/ ,輸出結果為:GET 方法
檢視層views.py檔案
from django import views class MyloginView(views.View): def get(self, request): return HttpResponse('from CBV get function') def post(self,request): return HttpResponse('from CBV post function')
路由層urls.py檔案
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('login/',views.MyloginView.as_view()) ]
CBV會自動根據請求方法的不同自動匹配對應的方法並執行
path('login/', views.MyLoginView.as_view()) # as_view() 是什麼東西
我們 Ctrl + 點選檢視其原始碼
發現它是一個類方法, 檢視其整體結構(只看框起來的即可, 其他的不用管), 該方法內部有一個 view
方法, 並且返回值是 view
的記憶體地址, 類似於閉包函數
於是我們就可以得到一些初步結果
path('login/', views.MyLoginView.as_view()) # 等同於下面 path('login',views.view) # 看著是不是與普通的路由沒有什麼區別了 : 通過匹配觸發檢視函數的執行
那麼 view
是一個什麼樣的函數呢? 現在突破口變成了 view
方法了
我們再看其原始碼(只看框起來的即可,其他的不用管) :
"self = cls(**initkwargs)" # cls是什麼? 記得上面的類方法嗎? 類呼叫時傳入類本身 # 我們是通過MyView來呼叫as_view的, 那麼cls也就是MyView # 類加括號範例化得到物件self, 這個self就是我們自己的類產生的物件 : self=MyView(**initkwargs),我們不用去管裡面的引數 # 接下來看看view的返回值 : self.dispatch(request, *args, **kwargs) # 也就是去MyView類範例出的物件裡面去找dispatch方法並執行,很顯然self物件中沒有該方法,於是去類中去找,也沒有 # 最後到父類別View中去找,發現就在as_view類方法的下面找到了
我們在看它下面的邏輯程式碼
邏輯很簡單,使用了反射的知識點
# 先是拿到當前請求方式的大寫字元轉成小寫, 然後判斷在不在後面的 self.http_method_names 裡面 # Ctrl+點選 看看這是個什麼東西 : 'http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']' # 發現是8種常用的請求方式列表, 接著返回dispatch原始碼檢視,為了方便我們假設現在的是get請求方式 # 判斷get請求在請求列表裡面,於是執行緊跟其下的程式碼...我們先看看getattr()得到的是什麼結果 # 判斷我們的self是否有名叫get的屬性或方法,如果有則返回該屬性的值或方法的記憶體地址,否則返回 self.http_method_not_allowed, 這是個啥,我們 Ctrl+點選 也來看看:
# 原來是一個報錯資訊 : 提示方法不允許,整理下思路,也就是說self中有get返回值或者記憶體地址,沒有則報錯 # 很顯然我們的self是有get這個名字的,並且是一個方法,於是將get方法的記憶體地址賦值給handler # 我們再來看dispatch的返回值 : handler + (括號), 不就是執行該方法嗎!也就是執行了我們的get方法列印了"觸發了get方法--->"