期待已久的装饰器终于闪亮登场!!!
1装饰器
定义 : 在不改变原函数的调用方式和函数 额外的增加功能
新建一个python文件 在里面写
引入:定义一个函数 要求 函数被调用执行时 打印一下执行的时间(引入事件模块)
可以定义一个时间函数 将需要执行的函数传入到时间函数里面 这样就可以了
问题 : 这样就改变了函数的调用方式
import time def timer(func): def inner(): print(time.time()) ret = func() # 原来的函数 return ret return inner def func1(): print(func1) return 'func1的返回值' a = timer(func1) # 此时返回值是inner的返回值 a() #还是改变了调用方式 # 用下边的 func1 = timer(func1) func1() #这样就调用方式就不变了 #装饰器是闭包的一种应用
# 也可以这样用 这样是利用语法的情况使用装饰器
@timer # 等同于func1 = timer(func1)
def func1():
print(func1)
return 'func1的返回值'
func1()
用到了闭包
实例代码
# 定义约会函数 # 需要先下载软件 def download(func): # 给函数增加功能 def inner(): print('下载软件') func() return inner # 使用不同工具约 #def yue(tools): # print('使用{}约一约'.format(tools)) # yue = download(yue) @download def yue(tools): print('使用{}约一约'.format(tools)) # 原函数携带参数 yue('momo') # 现在是装饰器中的inner yue('tantan') yue('漂流瓶')
完整的装饰器的写法
# 规范写法 def wrapper(func): def inner(*args,**kwargs): # 执行被装饰函数之前的操作 ret = func(*args,**kwargs) # 执行被装饰函数之后进行的操作 return ret return inner # 对函数进行装饰 @wrapper def func1(): print('func1') func1()
装饰器的进阶内容:
# 对多个装饰器进行控制 # 定义一个开关 # 全局定义一个 # flag = True # if #判断 flag import time flag = True def outer(flag): def timer(func): def inner(*args,**kwargs) if flag: print(time.time()) ret = func(*args,**kwargs) else: ret = func(*args,**kwargs) return ret return inner @outer(True) def func1(): print('func1') 会执行装饰器 @outer(False) def func2(): print('func2') func1() func2()
打印结果我们会发现 func2函数没有打印时间 也即对func2实现了写了装饰器但没有添加装置器的效果
多个装饰器装饰同一个函数:
#固定用法 def wrapper1(func1): def inner(*args,**kwargs): print('wrapper1 前') #2 ret = func(*args,**kwargs) print('wrapper1后') #5 return ret return inner def wrapper2(func2): def inner(*args,**kwargs) print('wrapper2前') #1 ret = func(*args,**kwargs) print('wrapper2后') #4 return ret return inner @wrapper2 # func1 = wrapper2(func1) wrapper2.inner @wrapper1 # func1 = wrapper1(func1) wrapper1.inner
#func = func1 def func1(): print('func1') #3 return 'func1的返回值' print(func1()) # 6
# 这样走的思路 首先 wrapper1先对func1进行装饰 装饰完之后 func1 = wrapper(func1) 即此时的
#func1实际上是wrapper1的inner函数 再进行装饰也即将wrapper1的inner函数进行装饰
#即func1 = wrapper1的inner函数 所以最终的显示结果为 先执行wrapper2的inner函数 打印'wrapper2前'
#接着往下执行,此时的函数为wrapper1的inner函数 即跳转到wrapper1中,打印'wrapper1前',再接着执行的就
#是wrapper1里面的包裹的函数也即真正的func1 打印'func1' 接着往下执行 打印'wrapper1后'接着返回d到
'wrapper2后' 执行完装饰器 接着就是执行自身的返回值
# 执行完就返回本身 接着再往下进行
可以用此图理解 装饰之后按顺序进行显示 每一层执行完之后就返回本身 接着继续向下进行
装饰器修复技术:
# 需求 要知道是哪个函数执行的 #print(func1(__name__)) #from functools import wraps # 将 @wraps(func)放入到inner上边就可以 import time from functiontools import wraps def timer(func): @wraps(func) def inner(): print(time.time()) ret = func() # 原来的函数 return ret return inner @timer # func1 = timer(func1) def func1(): """ func1 xxxx :return: """ print('func1') return 'func1的返回值' @timer # func1 = timer(func1) def func2(): """ func2 xxxx :return: """ print('func2') return 'func2的返回值' print(func1.__name__) print(func2.__name__) print(func2.__doc__) # 加了此行就会显示出函数2的注释 在日志中加入此项就可以辨别出到底是哪个函数执行的 显示结果为 func1 func2 func2 xxxx :return:
2视图系统
1 CBV和FBV
FBV(function based view)
CBV(class based view)
我们之前写过的都是基于函数的view,就叫FBV.还可以把view 写成基于类的.
写CBV的步骤:
1 定义:
# 增加出版社 CBV from django.views import View class AddPublisher(View): def get(self, request): pass def post(self, request): pass
2 使用:
url(r'^add_publishe/',views.AddPublisher.as_view()) #一定要有括号 才能执行
3 CBV的流程:
1:
views.AddPublisher.as_view() 程序加载的时候执行 view函数
2:当请求到来的时候执行view函数: 1 self = AddPublisher() 2 self.request = request 3:执行self.dispatch方法 : 1 判断请求方法是否被允许 允许时 通过反射获取到AddPublisher中定义的get或者post的方法 通过handler 不允许时self.http_method_not_allowed 也是通过handler拿到 2 执行handler拿到返回结果 HttpResponse对象
4 . 给CBV加装饰器
from django.utils.decorators import method_decorator
1 加载某个get/post的方法上:
@method_decorator(timer) def get(self,request): #2加载self.dispatch方法上 (推荐用法) @method_decorator(timer) def dispatch(self,request,*args,**kwargs); #3加在类上 @method_decorator(timer,name='post') # 必须有name字段 指定给哪一种方式加装饰器 @method_decorator(timer,name='get') class AddPublisher(view):
简例如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class AddPublisher(View): #可以自己定义request的方法 # http_method_names = ['get'] @method_decorator(timer) def dispatch(self, request, *args, **kwargs): # 操作 # start = time.time() ret = super().dispatch(request, *args, **kwargs) # end = time.time() # print('时间:{}'.format(end - start)) # 操作 return ret # @method_decorator(timer) def get(self, request): print('get') return render(request, 'add_publisher.html') # @method_decorator(timer) def post(self, request): print('post') err_msg = '' new_name = request.POST.get('new_name') if not new_name: err_msg = '不能为空' obj_list = models.Publisher.objects.filter(name=new_name) if obj_list: err_msg = '数据已存在' if new_name and not obj_list: ret = models.Publisher.objects.create(name=new_name) return redirect('/publisher_list/') return render(request, 'add_publisher.html', {'err_msg': err_msg, 'new_name': new_name})
2 request
request.method # 判断请求方式 request.GET # 获取url上的信息 类似于字典的东西 可以通过get() 或者[]获取 request.POST #获取form表单上提交的POST数据 request.body # 请求体 request.POST的数据就是从body里获取的 request.FILES #一个类似于字典的对象 包含所有上传文件信息 #需要注意 #1 . form表单中需要添加 enctype enctype = 'multipart/form-data' #2 .将方法改为post 添加name属性 添加{% csrf_token %} method = 'post' name='' {% csrf_token %} #3 .注意设置文件对象的方法 chunks # 上传文件 def upload(request): if request.method =='POST': file = request.FILES.get('f1') with open(file.name, 'wb') as f: for chunk in file.chunks(): f.write(chunk) return HttpResponse('上传成功') return render(request,'upload.html') # html页面 <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} 文件:<input type="file" name="f1"> <button>上传</button> </form>
JsonResponse
JsonResponse是HttpResponse的子类 专门用来生成JSON编码的响应
from django.http import JsonResponse def json_test(request): data = {'name':'dsb','age':'12'} return JsonResponse(data) #第二种方法 自己手动设置返回值 def json_test(request): data = {'name':'dsb','age':'25'} return HttpResponse(json.dumps(data),Content-Type='application/json')