视图函数,简称视图,一般定义在views.py;用于接受web请求与相应请求,相应地有请求对象HttpRequest对象、HttpResponse对象,我们前面的学习也用到这两个对象的一些方法。
一、HttpRequest对象
当有web请求时,Django会创建一个包含本次请求信息的HttpRequest对象并将其传递给urls定义的视图层函数,而我们应当约定俗成地使用request形参来接收它。
常用方法
path | 获取用户访问的路由,但拿不到参数 |
---|---|
path_full_path | 能获取用户完整的资源,包括域名、路由、参数 |
method | 获取请求的HTTP方法(get post put head delete connect options trace),全大写表示。 |
GET | 获取用户get请求的所有相关参数 |
POST | 获取用户post请求的所有相关参数 |
FILES | 获取用户POST提交的文件对象。 |
body | 原生的浏览器发过来的二进制数据 |
二、HttpResponse对象
3.1、HTTPresponse
为客户端返回字符串类型,常见方法有
- HttpResponse.content:响应内容。
- HttpResponse.charset:响应内容的编码。
- HttpResponse.status_code:响应的状态码。
3.2、render
返回HTML页面,且在返回给浏览器前还可以给它传值
3.3、redirect
重定向
视图函数必须要返回一个HTTPresponse对象,而render和redirect源码其实都是继承了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)
三、JsonResponse对象
JsonResponse是HttpResponse的子类,专用于转换数据格式为json格式以实现跨语言数据交互。
3.1、基本使用
我们以前都是使用json模块来对数据进行转换,而Django则帮我们封装了json模块。
JsonResponse({'sanxi':666})
# 这个JsonResponse默认只能序列化字典类型,如需序列化其它类型需要指定参数safe
JsonResponse([123, 222], safe=False)
# 原生json中文等编码默认自动转为Unicode,如果不想转码需要指定ensuure_ascii=false,在Django中更麻烦了
# 我们去看下JsonResponse的源码就知道了
3.2、JsonResponse源码
class JsonResponse(HttpResponse):
"""
An HTTP response class that consumes data to be serialized to JSON.
:param data: Data to be dumped into json. By default only ``dict`` objects
are allowed to be passed due to a security flaw before EcmaScript 5. See
the ``safe`` parameter for more information.
:param encoder: Should be an json encoder class. Defaults to
``django.core.serializers.json.DjangoJSONEncoder``.
:param safe: Controls if only ``dict`` objects may be serialized. Defaults
to ``True``.
:param json_dumps_params: A dictionary of kwargs passed to json.dumps().
"""
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(JsonResponse, self).__init__(content=data, **kwargs)
看倒数第二行,这里的**json_dumps_params
默认是None,而接下来的代码为None则为空字典;那我们给他传一个字典的话就会被打散替换掉这个空字典,那么init的json_dumps_params会把这个键值对打散从而获得我们想要的类似json不转码ensuure_ascii=false的效果。
如下所示,很明显,这个办法不好用,越搞越麻烦。
JsonResponse('哈哈哈', safe=False, json_dumps_params={'ensure_ascii':False})
在JavaScript中序列化用的JSON
JSON.stringify()
JSON.parse()
四、上传文件
在学习HTML时我们知道,HTML使用form表单提交数据给后端,但是method必须是post,enctype必须是multipart/form-data
<form action="{% url 'study_index' %}" method="post" enctype="multipart/form-data">
</form>
且在后端views中,POST方法只能获取普通的键值对数据,对文件则不好用了,得用FILES方法。
def index(request):
if request.method == 'POST':
file_obj = request.FILES.get('filename') # 获取文件对象,其中get里面的参数是input:file里面的value的值
print(file_obj.name)
return render(request, 'login.html')
五、FBV与CBV
视图是可调用的,用于处理请求(request)和响应请求(response),在Django中,视图有两种形式:
- FBV,function base views,基于函数的视图,我们之前一直都是用的FBV。
- CBV,class base views,基于类的视图,本次主要讲解它。
基于类的视图和基于函数的视图都是为了让开发变得更加容易,二者跟Python的类和函数的区别是一样,函数是基础,类是更高级的设计。
5.1、CBV使用
CBV允许我们使用不同的函数来响应不同的请求方法,而无需像FBV那样使用if条件分支来判断请求方法!
urls.py代码
CBV的路由写法跟FBV有些不一样,CBV必须要用Django提供的方法as_view()。
from django.conf.urls import url
from study import views
urlpatterns = [
url(r'^index/', views.Myview.as_view())
]
views.py代码
需要导一个模块:from django.views import View
,要自动响应不同的请求方法就必须要定义该方法同名的函数。
from django.shortcuts import render, HttpResponse, redirect, reverse
from django.views import View
# Create your views here.
class Myview(View): # 所有视图的类必须要继承View
def get(self, request):
return HttpResponse('GET request')
def post(self, request):
return HttpResponse('POST request')
内部到底是怎么实现的?为什么一定要用as_views?它是被@staticmethod修饰的静态方法,还是被@classmethod修饰的类方法?
5.2、as_view源码分析
其实不用看源码也能猜到,因为我们定义的类里根本没有这个方法,这肯定是继承了View的方法属性。
在as_view源码里有下面这段代码,从最后面的return view可以看出url(r'^index/', views.Myview.as_view())
,在启动Django时就会立即执行as_view方法,立刻变形成url(r'^index/', views.view
在看Python源码时,要时刻记住面向对象属性查找顺序,看到self要明白这个self是谁。
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls是我们自定义的类,这里就是用我们定义的类实例化
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs) # 返回实例化产生的对象调用dispatch
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
再看dispatch方法,CBV的精髓所在。
def dispatch(self, request, *args, **kwargs): # self是我们自定义类实例化产生的对象
# 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: # 如请求方法在此列表中
# getattr,反射:通过字符串来操作对象的属性和方法
# handler = getattr(我们的类实例化产生的对象,请求方法,列表中找不到请求的属性方法时就会用第三个参数)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed) (对象,请求方法)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 自动调用请求方法所对应的函数
5.3、CBV添加装饰器
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator
# @method_decorator(csrf_protect, name='post') # 给指定方法添加装饰器,可多个。
class MyCsrfToken(View):
@method_decorator(csrf_protect) # 作用于当前类所有方法
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)
@method_decorator(csrf_protect) # 直接上装饰器
def get(self, request):
return HttpResponse('get')
def post(self, request)
return HttpResponse('post')