zoukankan      html  css  js  c++  java
  • 装饰器,视图系统 063

    期待已久的装饰器终于闪亮登场!!!


    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):          
     简例如下
    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})
        
    View Code
     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')
  • 相关阅读:
    ubuntu 14.4 apache2 django
    github上的版本和本地版本冲突的解决方法
    Javascript能做什么 不能做什么。
    django 取model字段的verbose_name值
    Django在admin模块中显示auto_now_add=True或auto_now=True的时间类型列
    合并多个python list以及合并多个 django QuerySet 的方法
    摘抄
    Python 字符串拼接
    学习HTTP
    Django 自定义模板标签和过滤器
  • 原文地址:https://www.cnblogs.com/f-g-f/p/10064160.html
Copyright © 2011-2022 走看看