Django-Part3——视图层
[TOC]
三板斧
HttpResponse
- HttpResponse:返回字符串类型
- render:返回html页面,并且在返回给浏览器之前还可以给html文件传值
- redirect:重定向
视图函数必须要返回一个HttpResponse对象
render
1 2 3 4 5 6 7 8
| def test(request): from django.template import Template, Context res = Template('<h1>{{ user }}</h1>') con = Context({'user': {'username': 'jason', 'password': 123}}) ret = res.render(con) print(ret) print(type(ret)) return HttpResponse(ret)
|
redirect
JsonResponse
- 前后端数据交互需要使用json作为过渡,实现跨语言传输数据。
1 2 3 4 5 6 7 8 9 10 11 12 13
| def ab_json(request): user_dict = {'username': 'jason好帅哦,我好喜欢!', 'password': '123', 'hobby': 'girl'} l = [111,222,333,444,555]
from django.http import JsonResponse return JsonResponse(user_dict, json_dumps_params={"ensure_ascii": False})
|
- 指将字典打散成关键字的形式
- 默认只能序列化字典,序列化其他需要加safe参数
很多时候都可以通过读源码来掌握用法
上传文件与后端操作
在 .html 中:
- method 必须指定成 post
- enctype 必须换成 multipart/formdata
使用requests模块上传
- Requests 使得上传多部分编码文件变得很简单
1 2 3 4 5 6 7 8 9 10 11
| >>> url = 'http://httpbin.org/post' >>> files = {'file': open('report.xls', 'rb')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
|
1 2 3 4 5 6 7 8 9 10 11
| >>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
|
1 2 3 4 5 6 7 8 9 10 11
| >>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "some,data,to,send\\nanother,row,to,send\\n" }, ... }
|
- 把多个文件组织到一个元组的列表中,其中元组结构为 (form_field_name, file_info)
1 2 3 4 5
| data = {'ts_id': tsid} files = [('images', ('1.png', open('/home/1.png', 'rb'), 'image/png')), ('images', ('2.png', open('/home/2.png', 'rb'), 'image/png'))] r = requests.post(url, data=data, files=files) print r.text
|
使用request接收文件
1 2 3 4 5 6 7 8 9 10
| def ab_file(request): if request.method == 'POST': print(request.POST) print(request.FILES) file_obj = request.FILES.get('file') print(file_obj.name) with open(file_obj.name, 'wb') as f: for line in file_obj.chunks(): f.write(line) return render(request,'form.html')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from werkzeug.utils import secure_filename def upload_file(request): if request.method == 'POST': uploaded_files = request.FILES.getlist("images") try: for file_obj in uploaded_files: file_name = secure_filename(file_obj.name) handle_uploaded_file(os.path.join(file_name), file_obj) result_json = {"msg": "success"} except Exception as e: result_json = {"msg": str(e)} return JsonResponse(result_json, safe=False)
def handle_uploaded_file(file_name, file_obj): try: with open(file_name, 'wb') as f: for chunk in file_obj.chunks(): f.write(chunk) except Exception as e: raise Exception('save %s failed: %s' % (file_name, str(e)))
|
request对象方法
get
请求携带的数据是有大小限制的,而post
请求则没有限制。
1 2 3 4 5
| def login(request): if request.method == 'POST': return HttpResponse("收到了 宝贝") return render(request, 'login.html')
|
- 对于
get
请求和post
请求应该有不同的处理机制
- 对
post
做特殊处理,而将request
放置在if
围绕之外,提高可阅读性
request.method
:返回请求方式,并且是全大写的字符串形式 <class ‘str’>
request.POST
:获取用户post请求提交的普通数据不包含文件
request.POST.get()
:只获取列表最后一个元素
request.POST.getlist()
:直接将列表取出
request.GET
:获取用户提交的get请求数据
request.GET.get()
:只获取列表最后一个元素
request.GET.getlist()
:直接将列表取出
request.FILES.get()
:用键取出对应的文件,是以字典形式封装好的
request.body
:发过来的原生二进制数据
request.path_info
:获取url(例如/app01/ab_file/
),和request.path是等效的
request.get_full_path()
:获取完整的url及问号后面的参数
可以使用以下装饰器来指定请求类型:
- @require_http_methods([“GET”])
- @require_http_methods([“POST”])
FBV与CBV
视图函数既可以是 函数 FBV(function base views),也可以是 类 CBV(class base views)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def index(request): return HttpResponse('index')
path("login/", views.login)
from django.views import View class MyLogin(View): def get(self,request): return render(request, 'form.html')
def post(self,request): return HttpResponse('post方法')
url(r'^login/', views.MyLogin.as_view())
|
CBV源码剖析
- 首先,不建议自己修改源码
- 函数名/方法名,加括号执行优先级最高,例如views.MyLogin.as_view()会立刻执行as_view()方法
- CBV与FBV在路由匹配上本质是一样的,都是路由对应函数内存地址。
- 在没有实例的情况下使用函数,则只可能使用@staicmethod或者@classmethod
- 在看python源码的时候,一定要时刻提醒自己面向对象属性方法查找顺序:
- 先从对象自己找
- 再去产生对象的类里面找
- 之后再去父类找
- …
- 反射 getattr()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| url(r'^login/', views.MyLogin.as_view()) url(r'^login/', views.view)
""" 函数名/方法名 加括号执行优先级最高 猜测: as_view() 要么是被@staicmethod修饰的静态方法 要么是被@classmethod修饰的类方法 正确 @classonlymethod def as_view(cls, **initkwargs): pass """
@classonlymethod def as_view(cls, **initkwargs): """ cls就是我们自己写的类 MyCBV Main entry point for a request-response process. """ def view(request, *args, **kwargs): self = cls(**initkwargs) return self.dispatch(request, *args, **kwargs) """ 以后你们会经常需要看源码 但是在看python源码的时候 一定要时刻提醒自己面向对象属性方法查找顺序 先从对象自己找 再去产生对象的类里面找 之后再去父类找 ... 总结:看源码只要看到了self点一个东西,一定要问你自己当前这个self到底是谁 """ return view def dispatch(self, request, *args, **kwargs): if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) """ 反射:通过字符串来操作对象的属性或者方法 handler = getattr(自己写的类产生的对象, 'get',当找不到get属性或者方法的时候就会用第三个参数) handler = 我们自己写的类里面的get方法 """ else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
|
模版语法
Django 模板语法个人不打算使用,故不记录。