视图层是实现业务逻辑的关键层
HttpResponse、render、redirect
视图函数必须要返回一个 HttpResponse 对象, 如果未返回, 会出现如下错误 :
提示你没有返回一个 HttpResponse 对象, 而是返回了一个 None
# 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格式
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 对象
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)
'''
]}>
'''
print(file_obj,type(file_obj))
'''
README.md
'''
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方法--->"