• python使用装饰器@函数式化django开发


    django是一个python web开发的框架。作为一个框架MVC的架构已经实现起来了。但是编码的时候你经常要进行进一步的抽象。

    AOP是一种称为面向切面的开发思想,意思是将部分功能代码在运行时动态的加载到指定位置。最常见的应用是Spring中的依赖注入@Autowired。

    而装饰器也可以被看成是一种AOP的实现,但是又有些许的不同,让我们来体会一下。

    在我们的实例中我们将django中的views.py(其实是controller层)拆出了implement.py(实现)和decorator.py(装饰器)

    1、先看我们的views.py。

    这里我们只给出一个接口做为演示。

    # -*- coding:utf-8 -*-
    import json
    import logging
    import implement
    import decorator
    from django.views.decorators.csrf import csrf_exempt
    
    logger = logging.getLogger(__name__)
    
    @csrf_exempt
    @decorator.impl_wrapper_check_time
    @decorator.process_time
    @decorator.cache
    def alarm_month_daytotal(request):
        if request.method == 'GET':
            time_str = request.GET.get('time')
            return implement.alarm_month_daytotal(time_str)
    

    alarm_total接口在views.py中的函数alarm_total中并没有返回JSONResponse对象,而是直接返回了调用implement.alarm_total()的结果,看样子是implement.alarm_total()返回了JSONResponse

    ,我们看看是不是这样。

    2、implement实现层

    # -*- coding:utf-8 -*-
    import json
    import logging
    import calendar
    
    from rediss import RedisCache
    from config import redis_config, alarm_status_mapping, alarm_type_mapping, alarm_level_mapping, combine_module, alarm_module_mapping,alarm_stage_mapping, 
        alarm_type_config_mapping, month_total_closed_mapping, month_total_tosolve_mapping
    from datetime import datetime, timedelta
    from dao import Dao as dash_dao
    from exceptions import DataEmptyException
    import time
    
    logger = logging.getLogger(__name__)
    
    # 按月获取分天报警情况
    def alarm_month_daytotal(time_str):
        time_object = datetime.strptime(time_str, '%Y-%m')
        month, length = calendar.monthrange(time_object.year, time_object.month)
        ret_list = [0 for i in range(length)]
        items = dash_dao.get_alarms_by_month(time_str)
        if not items:
            raise DataEmptyException('[table] %s' % 'alarm_list_table')
        for item in items:
            if not item.alarm_time:
                continue
            ret_list[at_day(item.alarm_time) - 1] += 1
        r = RedisCache(redis_config)
        key_list = r.keys("dmonitor:issue:%s*" % time_str)
        if not key_list:
            return ret_list
        for key in key_list:
            content = r.get(key)
            time_object = datetime.strptime(key.split(':')[2], '%Y-%m-%d')
            ret_list[time_object.day - 1] = {
                'y': ret_list[time_object.day - 1],
                'name': content,
                'marker': {
                    'symbol': 'url(/data_monitor/static/images/sun.png)'
                }
            }
        return ret_list

    并没有啊,implement.alarm_total()只返回了一个list对象。这是为什么呢?

    原因就在那几个装饰器的封装上。

    3、装饰器decorator

    impl_wrapper_check_time(func):执行装饰的装饰的func方法,并且对返回进行JSONResponse封装

    process_time(func):统计执行时间并打印日志

    cache(func):对接口的请求加入缓存

    执行顺序,装饰器装饰的顺序,从下往上我们例子里是cache->process_time->impl_wrapper_check_time那么:

    1、先执行impl_wrapper_check_time的开始部分

    2、然后是process_time时间的start_time记录

    3、cache缓存的准备

    4、被装饰的函数func

    5、cache缓存的返回

    6、process_time的end_time记录,并打印时间日志

    7、impl_wrapper_check_time返回JSONResponse

    执行顺序说明:

    1、异常也是按照这个顺序一级一级的向上抛出。

    2、最终由impl_wrapper_check_time处理异常,返回errno:0或者-1。

    3、先执行完缓存的返回,再执行时间的统计,这样可以明显观察到缓存对处理时间性能上的提升。

    import logging
    import time
    import json
    import traceback
    from rediss import RedisCache
    from config import redis_config, cache_timeout, cache_switch
    from exceptions import IllegalParamException
    from django.http import JsonResponse
    from django.http import HttpResponse
    
    logger = logging.getLogger(__name__)
    
    redis = RedisCache(redis_config)def impl_wrapper_check_time(func):
        def wrapper(*args, **kwargs):
            try:
                if args[0].method == 'GET':
                    if not args[0].GET.get('time'):
                        raise IllegalParamException('time')
                data = func(*args, **kwargs)
                return JsonResponse({'errno': 0, 'msg': 'success', 'data': data})
            except Exception, ex:
                logger.error(traceback.format_exc())
                return JsonResponse({'errno': -1, 'msg': str(ex)})
    
        return wrapper
    
    
    def process_time(func):
        def wrapper(*args, **kwargs):
            path = args[0].get_full_path()
            start_time = time.time()
            data = func(*args, **kwargs)
            end_time = time.time()
            logger.info('path: %s, process_time: %s ms' % (path, str((end_time - start_time) * 1000)))
            return data
        return wrapper
    
    
    def cache(func):
        def wrapper(*args, **kwargs):
            if not cache_switch:
                data = func(*args, **kwargs)
                return data
            path = args[0].get_full_path()
            dashboard_cache_key = 'dashboard:cache:%s' % path
            if redis.get(dashboard_cache_key):
                logger.info('[Hit Cache] path: %s' % path)
                return json.loads(redis.get(dashboard_cache_key))
            data = func(*args, **kwargs)
            redis.set(dashboard_cache_key, json.dumps(data))
            redis.expire(dashboard_cache_key, cache_timeout)
            logger.info('[Query] path: %s' % path)
            return data
        return wrapper
  • 相关阅读:
    laravel的验证码
    laravel的中间件
    laravel的基本使用
    laravel的路由
    layui上传文件的choose只触发一次
    宝塔访问站点上一级目录
    orcale的几个查询
    tree的递归,适合与el-tree
    GIT 命令大全
    Oracle 时间戳与日期的转换
  • 原文地址:https://www.cnblogs.com/kangoroo/p/7265025.html
Copyright © 2020-2023  润新知