視圖層是實現業務邏輯的關鍵層html
HttpResponse、render、redirect前端
視圖函數必需要返回一個 HttpResponse 對象, 若是未返回, 會出現以下錯誤 :python
提示你沒有返回一個 HttpResponse 對象, 而是返回了一個 Nonedjango
# HttpResponse # render 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) # 返回一個HttpResponse對象 # redirect 內部繼承了 HttpResponse 類
import json def test(resquest): user_info = {"name":"shawn","age":23,"sex":"male","hobby":"吃飯"} data = json.dumps(user_info,ensure_ascii=False) return HttpResponse(data)
添加
ensure_ascii=False
參數是爲了讓中文保持正常顯示, 否則會轉換成uncode格式json
from django.http import JsonResponse def test2(request): user_info = {"name":"shawn","age":23,"sex":"male","hobby":"吃飯"} return JsonResponse(user_info)
疑問 : JsonResponse 對象沒有
ensure_ascii
參數來保證中文正常顯示嗎?後端解決方法 : 查看 JsonResponse 源碼跨域
那咱們就爲其傳入
json_dumps_params( )
參數閉包
return JsonResponse(user_info, json_dumps_params={'ensure_ascii':False}) # 測試能夠正常顯示中文
safe=False
參數, 讓其容許非 dict 對象被序列化from django.http import JsonResponse def test1(request): ll = [1,2,3,43,4] return JsonResponse(ll, safe=False,json_dumps_params={'ensure_ascii':False})
ps : JsonResponse 返回的也是 HttpResponse 對象app
class JsonResponse(HttpResponse): # 繼承了HttpResponse ...
post
提交multipart/form-data
<body> <div class="container"> <div class="col-md-8 col-md-offset-2"> <form action="" method="post" enctype="multipart/form-data"> <input type="file" class="form-control" name="myfile"> <input type="submit" class="btn btn-warning btn-block" value="提交"> </form> </div> </div> </body>
def form_test(request): if request.method == "POST": # 從文件對象字典中獲取名爲"myfile"的文件對象 file_obj = request.FILES.get('myfile') file_name = file_obj.name # 保存方式一: with open(f'./{file_name}',"wb")as f: for line in file_obj: f.write(line) # 保存方式二:(官方推薦) with open(f'./{file_name}',"wb")as f: for line in file_obj.chunks(): f.write(line) return render(request,'test.html') # 打印個別結果看看 print(request.FILES) ''' <MultiValueDict: {'myfile': [<InMemoryUploadedFile: README.md (application/octet-stream)>]}> ''' print(file_obj,type(file_obj)) ''' README.md <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> ''' print(file_obj.name) ''' README.md ''' # 官方推薦寫法 chunks() 的源碼 def chunks(self, chunk_size=None): self.file.seek(0) yield self.read() # 一個迭代器
# views.py 文件 from django.views import View def test_func(request): return render(request,'test.html') class MyView(View): def get(self,request): return HttpResponse('觸發了get方法--->') def post(self,request): return HttpResponse('觸發了post方法--->') # urls.py 文件 from django.urls import path,re_path,include from app02 import views urlpatterns = [ re_path(r'^test/',views.test_func), re_path(r'^func',views.MyView.as_view()) ] # 模板文件 test.html <div> <form action="/func/" method="post" enctype="multipart/form-data"> <input type="file"> <input type="submit"> </form> </div>
那麼爲何就能根據不一樣的操做來觸發不一樣發那個發的執行呢?函數
re_path(r'^func',views.MyView.as_view()) # as_view() 是什麼東西
咱們 Ctrl + 點擊查看其源碼
發現它是一個類方法, 查看其總體結構(只看框起來的便可, 其餘的不用管), 該方法內部有一個
view
方法, 而且返回值是view
的內存地址, 相似於閉包函數
因而咱們就能夠獲得一些初步結果
re_path(r'^func',views.MyView.as_view()) # 等同於下面 re_path(r'^func',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方法--->"