一、视图层之必会三板斧

之前我们简单学习了三板斧的使用,这里我们进行一些深入的了解。

视图函数不写返回值会报错,报错信息如下:

这里就引出了今天的话题。这里我们需要记住一个定论:用来处理请求的视图函数都必须返回HttpResponse对象

在之前学习的时候我们对HttpResponse的作用仅限于知道他是用来给网页传递字符数据的。

从正面不容易证明上面的定论,我们可以从三板斧的源码中进行确认。

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的内部源码,在他的返回值中我们可以发现他的返回值也是用HttpResponse类产生的一个对象。

redirect

def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))

这里我们可以直接的看到返回的结果时redirect_class这个变量,而这个变量的值是有两种情况,用三元表达式进行简写了,依旧是用ctrl+鼠标左键,我们点击他们,会发现他两分别是两个不同的类,但是同时继承了一个名叫HttpResponseRedirectBase的父类

class HttpResponseRedirect(HttpResponseRedirectBase):
status_code = 302 class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
status_code = 301

接下来我们去看这个父类有什么花头。

我们可以在这两个类的源代码上方找到这个父类,咋们也不用管他干了什么,首先我们就会发现这个类他的父类是HttpResponse

class HttpResponseRedirectBase(HttpResponse):
allowed_schemes = ['http', 'https', 'ftp'] def __init__(self, redirect_to, *args, **kwargs):
super().__init__(*args, **kwargs)
self['Location'] = iri_to_uri(redirect_to)
parsed = urlparse(str(redirect_to))
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) url = property(lambda self: self['Location']) def __repr__(self):
return '<%(cls)s status_code=%(status_code)d%(content_type)s, url="%(url)s">' % {
'cls': self.__class__.__name__,
'status_code': self.status_code,
'content_type': self._content_type_for_repr,
'url': self.url,
}

当一个类的爷爷继承了HttpResponse,那么这个类产生的对象其实就是由HttpResponse产生的(如果不理解的可以回头看看类的双下new方法产生对象的过程)。

HttpResponse

他就是用类名加括号的形式返回值,相当于是返回了一个对象,符合上面的定论。

通过上面的一圈论证,我们就可以证明我们的定论是正确的。

二、JsonResponse对象

当我们给前端页面传递数据的时候,有些时候可能会出现跨语言交互数据的情况,这时候我们需要使用json模块来序列化数据,让数据实现跨语言传输。

在html网页中我们使用js语言中的JSON对象进行序列化和反序列化

JSON.stringify()
JSON.parse()

python中我们使用json模块进行序列化和反序列化

json.dumps()
json.loads()

两种序列化数据的方式

方式一:使用json模块

def index_func(request):
# 返回给浏览器一个json格式的字符串
user_dict = {'name': 'jason老师', 'age': 18}
import json
user_json = json.dumps(user_dict, ensure_ascii=False)
return HttpResponse(user_json)

使用json序列化数据需要先转换格式,再交给HttpResponse返回给浏览器

方式二:使用JsonResponse对象

from django.http import JsonResponse
def index_func(request):
user_dict = {'name': 'jason老师', 'age': 18}
return JsonResponse(user_dict)

使用JsonResponse对象,直接输出数据就好了,他的源代码中已经用json模块处理过数据了。同时也省去了调用HttpResponse返回给浏览器数据的步骤。

ps:以后写代码很多时候可能需要参考源码及所学知识扩展功能

使用JsonResponse对象序列化除字典外的数据类型

接下去当我们尝试使用不同数据类型的数据,通过JsonResponse对象返回给浏览器的时候,除了字典类型的数据都会出现报错,通过查看源码我们得知是safe参数导致的主动报错。

这里是JsonResponse部分源码

class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
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.'
)

因为JsonResponse主要序列化字典,所以针对非字典的其他可以被序列化的数据需要修改safe参数为False

如果给JsonResponse对象内部的json代码传参

解决了数据类型的传递问题,我们又想到针对字符编码需要使用ensure_ascii=False让中文字符不变成二进制。通过观察源码,我们发现如果想要传参,是通过json_dumps_params这个变量来传递其他参数的。通过查看源码的运行,我们发现直接用关键字参数的形式在JsonResponse对象的括号内传参即可。

完整源码如下

class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
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 = {}
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)

三、视图层之request对象获取文件

我们使用表单标签中的input标签接收用户的输入以及其他数据

form表单携带文件类型的数据需要做到以下几点

1.method必须是post

2.enctype必须是multipart/form-data

    <form action="" method="post" enctype="multipart/form-data">
<p>file:
<input type="file" name="file">
</p>
<input type="submit" value="选我">
<button>点我</button>
</form>

django后端需要通过request.FILES获取文件类型的数据

def index_func(request):
if request.method == 'POST':
# print(request.POST) # 获取普通数据(输入、选择)
# print(request.FILES) # 获取文件数据(上传)
file_obj = request.FILES.get('file')
print(file_obj.name) # 获取文件名称
with open(r'%s' % file_obj.name, 'wb') as f:
for line in file_obj: # 文件对象支持for循环一行行读取内容
f.write(line)
return render(request, 'indexPage.html')

四、视图层之FBV与CBV

概念介绍

视图是可调用的,用来处理请求(request)并且返回响应(response),django的视图有两种形式:FBV和CBV

1、FBV基于函数的视图(Function base views),我们之前一直介绍的都是FBV

2、CBV基于类的视图(Class base views),我们本节主要介绍它

视图函数可以是函数也可以是类

代码展示:

FBV

# urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('fbv/', views.test_fbv),
]
# views.py
def index(request):return HttpResponse对象

CBV

# urls.py
from django import views
urlpatterns = [
path('login/', views.MyLoginView.as_view())
]

这里就是CBV形式,也就是类的路由导入,这时候我们就不需要写对应的对象内的方法了,会自动匹配并执行

# views.py
"""只要是处理业务逻辑的视图函数 形参里面肯定要有request"""
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')

五、CBV源码剖析(重要)

1.从CBV的路由匹配切入

path('login/', views.MyLoginView.as_view())
1.类名点名字(名字的查找问题)
2.类名点名字并加括号调用(静态方法、绑定给类的方法)

2.函数名加括号执行优先级最高 项目一启动就会自动执行as_view方法

部分View源码

class View:

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    @classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs

我们可以看到在源码中as_view返回的结果时view,而view是as_view内部的一个闭包函数。因此CBV路由导入的结果其实和FBV的路由导入代码一样,相当于FBV中的路由导入:

path('login/', views.view)
# as_view 可以看成view

因此可以得出结论:CBV路由本质还是FBV

3.浏览器地址栏访问login路由需要执行view函数

1.产生我们自己编写类的对象

部分源码

def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)

首先是开头的self变量,他相当于产生了一个对象,而这个对象使用我们自己定义的那个类来产生的,接着中间的都不重要,在末尾return的位置我们发现产生的这个对象调用了dispatch方法。

2.对象调用dispatch方法(注意查找顺序)

4.研究父类中的dispatch方法

获取当前请求方法并转小写,之后利用反射获取类中对应的方法并执行。

	因为我们没有定义这个dispatch方法,所以会调用父类中的dispatch方法,第一个if语句判断的是我们的请求方法,判断他是否在view类中定义的第一行的变量名内。如果有这个方法名称就用反射获取结果,没有结果就返回报错信息。
	http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)

django视图层与cbv源码分析的更多相关文章

  1. Django框架(十七)-- CBV源码分析、restful规范、restframework框架

    一.CBV源码分析 1.url层的使用CBV from app01 import views url(r'book/',views.Book.as_view) 2.as_view方法 as_view是 ...

  2. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...

  3. Django框架(十八)—— CBV源码分析、restful规范、restframework框架

    目录 CBV源码分析.restful规范.restframework框架 一.CBV源码分析 1.url层的使用CBV 2.as_view方法 3.view方法 4.dispatch方法(可以在视图层 ...

  4. drf-day2——restful规范、序列化反序列化、基于django编写五个原生接口、drf介绍和快速使用、cbv源码分析

    目录 一.restful规范(重要,不难) 概念 十个规范 二.序列化反序列化 三.基于django原生编写5个接口 四.drf介绍和快速使用 概念 安装 代码 五.cbv源码分析 六.作业 1.使用 ...

  5. CBV源码分析+APIVIew源码分析

    {drf,resful,apiview,序列化组件,视图组件,认证组件,权限组件,频率组件,解析器,分页器,响应器,URL控制器,版本控制} 一.CBV源码分析准备工作: 新建一个Django项目 写 ...

  6. drf快速使用 CBV源码分析 drf之APIView分析 drf之Request对象分析

    目录 序列化和反序列化 drf介绍和安装 使用原生django写接口 django DRF安装 drf快速使用 模型 序列化类 视图 路由 datagrip 使用postman测试接口 CBV源码分析 ...

  7. Django的settings文件部分源码分析

    Django的settings文件部分源码分析 在编写Django项目的过程中, 其中一个非常强大的功能就是我们可以在settings文件配置许多选项来完成我们预期的功能, 并且这些配置还必须大写, ...

  8. FBV与CBV 及CBV源码分析

    FBV与CBV 及CBV源码分析 FBV(Function Based View) 基于函数的视图 基于函数的视图,我们一直在用没啥好讲的,就是导入模块调用函数执行业务 CBV(Class Based ...

  9. $Django cbv源码分析 djangorestframework框架之APIView源码分析

    1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...

  10. DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用

    CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()),  --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...

随机推荐

  1. PRT预计算辐射传输方法

    PRT(Precomputed Radiance Transfer)技术是一种用于实时渲染全局光照的方法.它通过预计算光照传输来节省时间,并能够实时重现面积光源下3D模型的全局光照效果. 由于PRT方 ...

  2. SIGIR2024| RAREMed: 不放弃任何一个患者——提高对罕见病患者的药物推荐准确性

    SIGIR2024| RAREMed: 不放弃任何一个患者--提高对罕见病患者的药物推荐准确性 TLDR:在本文中,我们针对药物推荐模型对罕见病患者推荐精度低的问题,提出了一种新的基于预训练-微调的药 ...

  3. AI五子棋_02_03 Get传输数据 公共密钥

    AI五子棋 第二步 恭喜你到达第二步! 警告:如果你是直接使用浏览器获得本页地址的话,请你返回第一步. 在前一步里,你得到的这样的返回结果 {"is_success": true, ...

  4. mini-web框架 添加log日志

    阅读目录: 1.mini-web框架-路由支持正则 2.mini-web框架-mysql-增 3.mini-web框架-mysql-删 4.mini-web框架-mysql-改 5.mini-web框 ...

  5. python处理大量数据excel表格中间格式神器pickle.pkl文件操作说明

    读取写入千万级别的excel文件费时费力,调试起来比较慢,面对这个问题,第一步可以先无脑全部转换成pkl文件,这样几乎和内存操作一样的速度. 例如: t=pd.read_excel("12月 ...

  6. C++之OpenCV入门到提高003:矩阵的掩膜(Mask)处理

    一.介绍 今天是这个系列<C++之 Opencv 入门到提高>得第三篇文章.今天这篇文章也不难,主要介绍如何使用 Opencv 对图像进行掩膜处理,提高图像的对比度.在这个过程中,我们可以 ...

  7. 使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究

    本人之前对C#开发非常喜欢,也从事开发C#开发桌面开发.Web后端.Vue前端应用开发多年,最近一直在研究使用Python,希望能够把C#的一些好的设计模式.开发便利经验引入到Python开发中,很多 ...

  8. 利用DbgHelp获取线程的栈回溯信息

    当线程发生异常时,我们如果可以记录下来异常线程的堆栈信息,那么对于我们后续问题处理将会有极大的帮助.这里记录一个操作方法. 1 #include <iostream> 2 #include ...

  9. 3.20 什么是环境变量,Linux环境变量有哪些?

    变量是计算机系统用于保存可变值的数据类型,我们可以直接通过变量名称来提取到对应的变量值.在 Linux 系统中,环境变量是用来定义系统运行环境的一些参数,比如每个用户不同的家目录(HOME).邮件存放 ...

  10. 4-1 C++运算符基本概念

    目录 4.1.1 基本概念 函数观点 左值和右值 运算符重载 4.1.2 优先级.结合律与求值顺序 优先级和结合律 求值顺序 书中表述 实践表明(猜想) 实践验证 可能的解释:编译器的优化行为 一些运 ...