Django之视图层
JsonResponse
向前端返回一个json格式字符串的两种方式
方式一:
import jsondef json_data(request):user_dict = {'name': 'kevin', 'age': 22, 'hobby': '足球'}dict_json = json.dumps(user_dict, ensure_ascii=False)return HttpResponse(dict_json)
方式二:
def json_data(request):user_dict = {'name': 'kevin', 'age': 22, 'hobby': '足球'}return JsonResponse(user_dict, safe=False, json_dumps_params={'ensure_ascii': False})
- 默认
safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象 - 只所以使用
JsonResponse是因为django对json序列化的数据类型的范围做了扩充
form表单上传文件
演示
urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^register/$', views.register),]
view.py
def register(request):if request.method == 'POST':name = request.POST.get('name')header_img = request.FILES.get('header_img')with open(header_img.name, 'wb') as f:for line in header_img:f.write(line)return HttpResponse('注册成功')return render(request, 'register.html')
register.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><meta name="viewport" content="width=device-width, initial-scale=1"><link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"><script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script></head><body><div class="container"><div class="row"><h1 class="text-center">注册</h1><div class="col-lg-8 col-md-offset-2"><form action="" method="post" enctype="multipart/form-data">{% csrf_token %}<p>昵称:<input type="text" class="form-control" name="name"></p><p>头像:<input type="file" name="header_img" multiple></p><input type="submit" class="btn btn-success btn-block" value="注册"></form></div></div></div></body></html>
总结
form表单上传的数据中如果含有文件 那么需要做以下几件事
method必须是postenctype必须修改为multipart/form-data,默认是application/x-www-form-urlencoded- 后端需要使用
request.FILES获取(django会根据数据类型的不同自动帮你封装到不同的方法中)
request其他方法
request.method:获取请求方法request.GETorrequest.POST:获取GET or POST请求参数,字典形式。request.POST.get('name',default=None):获取POST请求参数request.GET.getlist('name',default=None): 获取GET参数列表request.META:包含当前HTTP请求的Headers头部信息, 字典形式。键值KEY都是大写。比如request.META['REMOTE_ADDR']可获取用户远程IP地址。request.user:获取当前访问用户的所有信息。request.path:获取当前访问路径request.FILES:获取上传文件的数据request.body:获取的是二进制数据(request.POST、request.GET、request.FILES这些获取数据的方法其实都从body中获取数据并解析存放的)request.path_info:获取当前访问路径request.get_full_path():获取路径并且还可以获取到路径后面携带的参数
FBV与CBV
django的视图层由两种形式构成:FBV和CBV
FBV
FBV基于函数的视图(Function base view)
urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^fbv/$',views.fbv),]
view.py
from django.shortcuts import render, HttpResponse, redirectdef fbv(request):return HttpResponse('from FBV')
CBV
CBV基于类的视图(Class base view)
urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^cbv/$', views.MyIndexView.as_view()),]
view.py
from django import viewsclass MyIndexView(views.View):def get(self, request):return HttpResponse('from CBV get view')def post(self, request):return HttpResponse('from CBV post view')
运行后的结果是:
如果请求方式是`GET`则会自动执行类里面的`get`方法;如果请求方式是POST 则会自动执行类里面的`post`方法
CBV源码解析
通过路由匹配做为切入点,`类名.as_view()`,(函数名加括号执行优先级最高)对象查找的顺序是先从自身,再从产生对象的类,再从父类。先从自己写的`MyIndexView`类中查找`as_view`,没有再去`MyIndexView`类中的父类查找,查看`View`类中找了`as_view`可以看到`Django` 给`as_vie`方法加了`@classonlymethod`装饰器,作用是只允许类对象调用这个方法(绑定给类的方法)。
@classonlymethoddef 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.getself.request = requestself.args = argsself.kwargs = kwargsreturn self.dispatch(request, *args, **kwargs)view.view_class = clsview.view_initkwargs = initkwargs# take name and docstring from classupdate_wrapper(view, cls, updated=())# and possible attributes set by decorators# like csrf_exempt from dispatchupdate_wrapper(view, cls.dispatch, assigned=())return view
可以看到最后返回的是一个return view ,view是一个闭包函数(定义在as_view函数内部的函数,并且内部还用到了外部名称空间的名字)。相当于url(r'^cbv/$', views.MyIndexView.as_view()),变成了url(r'^cbv/$', views.view()),可以推导出CBV与FBV在路由匹配本质是一样的。
当执行view函数,self = cls(**initkwargs)等同于self = MyIndexView(**initkwargs)意思是产生一个类的对象,最后返回的是一个self.dispatch(request, *args, **kwargs),继续查看dispath函数源码
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_allowedreturn handler(request, *args, **kwargs)
上述也就是CBV核心代码,可以看到返回的是 handler,handler用了反射中getattr(通过字符串获取对应的变量名或者函数名)
handler = getattr(自己写的类产生的对象, 'get', 当找不到get属性或方法就会用第三个参数)
简单说就是handler = 自己写的类里面的get方法
