Django之视图层
目录
视图层
一.三板斧
1.小白必会三板斧
-
HttpResponse
返回字符串类型
HttpResponse() 括号内直接跟一个具体的字符串作为响应体,比较直接简单,所以这里主要介绍后面两种形式。 -
render
返回html页面,并且在返回给浏览器之前还可以给html文件传值
render(request, template_name[, context])结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象 # 参数 request: 用于生成响应的请求对象。 template_name: 要使用的模板的完整名称,可选的参数 context: 添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它 render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
-
redirect
传递要重定向的一个硬编码的URL
def my_view(request): return redirect('/index/url') 也可以是一个完整的URL def my_view(request): ... return redirect('http://www.baidu.com/')
2.三板斧本质
视图app01没有返回一个HttpResponse对象,返回一个None代替了
django图层函数必须要返回一个HttpResponse对象
django视图层函数必须有一个返回值,并且返回值的数据类型必须是HttpResponse对象
2.研究三者的源码即可得出结论
1.def index(request):
return HttpResponse()
"""
按住ctrl点击进入HttpResponse:
发现HttpResponse其实是一个类,那么类名加()实例化产生一个对象
class HttpResponse(HttpResponseBase):
pass
"""
2.def index(request):
return render()
"""
按住ctrl点击进入render:
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
先执行的是render函数,然后render函数返回的是HttpResponse(content,content_type,status)
"""
3.def index(request):
return redirect()
"""
按住ctrl点击进入redirect:
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
按住ctrl点击进入HttpResponsePermanentRedirect:
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
pass
按住ctrl点击进入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
会发现它继承的也是HttpResponse
按住ctrl点击进入HttpResponseRedirect:
class HttpResponseRedirect(HttpResponseRedirectBase):
pass
按住ctrl点击进入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
会发现它继承的也是HttpResponse
"""
'''综上研究发现:Django视图层函数必须要返回一个HttpResponse对象'''
二.JsonResponse对象
def index(request):
# 将后端字典序列化发送到前端
user_dict = {'name': 'jason', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# 先转成json格式字符串
json_str = json.dumps(user_dict)
# 将该字段返回
return HttpResponse(json_str)
解决这个中文输入的问题我们之前是加了ensure_ascill=False,ensure_ascii 内部默认True自动转码,改为False不转码,只生成json格式,双引号
以上实现返回json格式数据比较麻烦,那么django的出现就在这方面做出了改变
JsonResponse
# 导入JsonResponse模块
from django.http import JsonResponse
def index(request):
user_dict = {'name': 'jason老师','pwd':123, 'hobby': ['read', 'run', 'music']}
# json_str = json.dumps(user_dict, ensure_ascii=False)
return JsonResponse(user_dict, json_dump_params={'ensure_ascii':False}) # 直接写入JsonResponse,不需要去做json序列化操作
# user_dict,json_dumps_params={'ensure_ascii':False} :解决前端中文转码问题
JsonResponse底层
# 继承了HttpResponse,返回的还是HttpResponse对象
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
# json_dumps_params=None,注意这个参数,是一个默认参数
if safe and not isinstance(data, dict):
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_dumps_params=None,
json_dumps_params = {}
# 如果我们在这里传入了一个值,那么这里的json_dumps_params = {'XXX':'XXX'},然后在下面的data里面转换为的是关键字参数,XXX=XX
kwargs.setdefault('content_type', 'application/json')
'''
将data数据进行了json序列化,然后做了一个返回
**json_dumps_param,**加在字典前面,现在是在调用一个函数,那么它在这里做实参,**在是实参中将字典打散为关键字参数形式,就是什么等于什么
'''
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
JsonResponse序列化(列表注意事项)
# 导入JsonResponse模块
from django.http import JsonResponse
def ab_json(request):
l = [111,222,333,444,555]
# 默认只能序列化字典 序列化其他需要加safe参数 safe=False
return JsonResponse(l,safe=False)
三.FBV与CBV
1.FBV与 CBV的区别
FBV是基于函数的视图(Function base view) 我们前面写的视图函数都是FBV
CBV基于类的视图(Class base view)
视图文件中除了用一系列的函数来对应处理客户端请求的数据逻辑外,还可以通过定义类来处理相应的逻辑。
# 视图函数既可以是函数也可以是类
def index(request):
return HttpResponse('index')
2.CBV
从index页面,后台修改action的参数,朝func发送post请求
点击提交以后自动发出了类里面的post方法
CBV比起FBV来说的话,不需要通过request.method来判断当前是什么请求,CBV会自动判断是哪种方法(写在类里面的函数叫做方法)
3.CBV底层源码剖析
从CBV的路由匹配切入
path('login/', views.MyLoginView.as_view())
"""
面向对象属性方法查找顺序
1.先从对象自己名称空间找
2.在去产生类对象的类里面找
3.在去父类里面找
"""
1.帮给类的as_view方法(它是我们自己写的类里面继承的类)
class View:
@classonlymethod # 相当于@classmethod
def as_view(cls, **initkwargs):
绑定给类的,类调用会自动将类当作第一个参数传入
def view(request, *args, **kwargs):
self = cls(**initkwargs)
return self.dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
handler = getattr(self, request.method.lower())
return handler(request, *args, **kwargs)
2.CBV路由匹配本质:跟FBV是一致的
path('func/', views.view)
3.访问func触发view执行
def view(...):
obj = cls() # 我们自己写的类加括号产生的对象
return obj.dispatch()
'''涉及到对象点名字 一定要确定对象是谁 再确定查找顺序'''
4.研究dispatch
def dispatch(...):
判断 request.method将当前请求方式转成小写 在不在 self内 self==MyLogin
"http_method_names 内有八个请求方式 合法"
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
if request.method.lower() in self.http_method_names:
# getattr 反射: 通过字符串来操作对象的属性或者方法
func_name = getattr(obj,request.method.lower())
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
用到了一个反射的知识,从obj这个对象里面,找一个request.method.lower()这个的函数