django之视图层
django之视图层
视图函数结构
视图函数的参数与返回值
每一个用来处理请求的视图函数,默认都需要一个request形参来接收request对象。
每一个用来处理请求的视图函数必须返回一个HttpResponse对象,包括我们三个响应函数:
-
HttpResponse(一些数据)
def func1(request):return HttpResponse("返回给网页的内容")
-
render(request, "html模板",{模板数据字典})
def func2(request):return render(request,"aaa.html",{"useronfo":userinfo,})
处理模板语法,返回html页面内容。
第一个参数传入request对象,第二个参数传入含有模板语法的html文件名(templates目录下),第三个参数则是传入模板语法可能用到的数据,我们可以通过字典的方式传入,也可以使用local()\global()
直接获取局部或者全局的所有名字传进去,好处是我们不必在给数据命名了,坏处是传数值不够精准,可能会浪费资源。 -
redirect(重定向的网址)
def func3(request):return redirect("/home")
重新向指定网址发送一个请求,内部的网址有三种形式:
"/路由":拼接域名和路由形成一个网址 "完整网址":本身就是域名+路由的形式的网址
-
JsonResponse(python数据)
from django.http import JsonResponse def func4(request): return JsonResponse({'a':'aaa','b','bbb'}) # 将Python字典数据处理成Json数据传给前端 def func5(request): user_dict = {'a':'大爷','b','bbb'} # 查源码可知,可以书写json序列化的参数,也可以让python数据不局限于字典 return JsonResponse(user_dict, json_dumps_params={ensure_ascii:False},safe=False)
对json源码的简析:
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict): # safe默认为真,为真时,只接收字典数据
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None: # 如果没有传入json序列化相关参数,就设置为空字典
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
关于返回值为HttpResponse对象这一点
第一个我们尚可理解,因为HttpResponse就是一个类,它所产生的的对象就是HttpResponse对象,我们将其返回出去,并最终传到浏览器,经过http渲染变成用户可以看到的内容。
后面三个是函数,而底层实际上是将函数的返回值设置为了HttpResponse对象。
视图函数request对象
我们可以通过路由层传输过来的request对象获取:
- GET:get请求携带的数据
- POST:post请求携带的数据
- FILES:表单标签提交的文件数据
form表单携带文件类型数据可以在form表单中添加两个属性:
- method属性得是post(因为文件大小一般较大)
- enctype属性可以是multipart/form-data
这样我们就可以通过request.FILES
得到一个文件字典,键为input标签的name属性,值为input标签提交的文件对象,我们可以对文件进行保存、读取等操作。
视图函数逻辑功能
视图函数作为我们的后端函数,它肩负着处理数据逻辑的功能,这也需要它能与数据库打交道,在请求生命流程图中也提到了,视图层通过模型层可以绕开sql语句来与对数据库的表进行增删改查。
而除了处理数据的逻辑,我们也需要对前端界面的一些元素做动态的处理,如将我们后端的变量数据传到前端页面中,或者对前端页面的某些标签做逻辑的处理,这些则需要用到模板语法了,在django项目中,这个工作就是通过render做的,它接收html页面和后端数据,对页面中的模板语法进行识别做后端的处理,最终将处理完的页面打包为HttpResponse对象。
视图层之FBV和CBV
FBV(fuction based view):基于函数的视图,上文所说的都是FBV
CBV(class based view):基于类的视图吗,与FBV有些许的不同。
CBV结构
视图文件中:
from django import views
class MyLoginView(views.View): # 视图类必须继承views.View
def get(self, request): # 根据请求方式命名的类体函数
return HttpResponse('from CBV get function') # 返回的还是HttpResponse对象
def post(self, request):
return HttpResponse('from CBV post function')
路由文件中:
from apps import views
..
path('login/', views.MyLoginView.as_view())
..
通过上面的代码得知,实际上CBV本质还是FBV,最终路由所索引到的函数还是视图类中的某个视图函数。
CBV源码剖析
-
views.MyLoginView.as_view()
与其他路由所对应的视图函数相比,CBV路由所对应的是视图类的某个方法,而这个as_view并不在我们定义的类中。那么as_view很有可能是我们继承的父类View中的,我们ctrl键跟上去查看。发现,as_view的返回值是一个函数,与我们其他路由所对应的视图函数相呼应,我们可以猜测这个函数返回值是一个视图函数。
-
带着这个猜想我们展开view函数进行查看:
发现这个返回值仍然不是一个明确的函数,我们还需要查看dispatch方法的返回值,在此之前,我们需要分析出,dispatch是绑定对象的动态方法,这个self是由我们自己定义的类所产生的对象。
-
查看dispatch函数,由于我们对象及其类的属性中都没有dispatch,所以这个函数还是我们父类View的类体函数:
至此,我们就剖析出,我们的as_view()函数做了这么几件事:
- 封装了一个函数,作为对应路由的函数
- 封装的函数中,让我们的自定义类产生了一个对象,并让对象执行方法dispatch返回结果
- dispatch辨认了请求方式,根据请求方式返回了某个类体函数的结果(HttpResponse对象)
所以视图类,就是将一个路由根据请求方式又重新划分了不同的视图函数,不必再在视图函数中对请求方式进行判断了。