278 lines
8.6 KiB
Python
278 lines
8.6 KiB
Python
"""
|
|
常用的装饰器以及DRF的装饰器
|
|
"""
|
|
import time
|
|
import traceback
|
|
from datetime import datetime
|
|
import functools
|
|
from collections import Iterable
|
|
from django.conf import settings
|
|
from rest_framework_extensions.settings import extensions_api_settings
|
|
from django.utils import six
|
|
from django.utils.decorators import available_attrs
|
|
from rest_framework.response import Response
|
|
from .string_util import bas64_encode_text, bas64_decode_text
|
|
|
|
|
|
def get_cache(alias=None):
|
|
from django.core.cache import caches
|
|
return caches[alias or extensions_api_settings.DEFAULT_USE_CACHE]
|
|
|
|
|
|
def print_fun_time(logger=None):
|
|
"""
|
|
打印函数执行时间
|
|
:param logger:
|
|
:return:
|
|
"""
|
|
def wrapper(func):
|
|
@functools.wraps(func)
|
|
def inner(*args, **kwargs):
|
|
start_time = datetime.now()
|
|
res = func(*args, **kwargs)
|
|
end_time = datetime.now()
|
|
seconds = (end_time - start_time).seconds
|
|
if logger:
|
|
logger.info(f"{func.__name__}耗时:{seconds}秒")
|
|
else:
|
|
print(f"{func.__name__}耗时:{seconds}秒")
|
|
return res
|
|
return inner
|
|
return wrapper
|
|
|
|
def print_time(logger=None):
|
|
"""
|
|
打印函数执行时间
|
|
:param logger:
|
|
:return:
|
|
"""
|
|
def wrapper(func):
|
|
@functools.wraps(func)
|
|
def inner(*args, **kwargs):
|
|
start_time = time.time()
|
|
res = func(*args, **kwargs)
|
|
end_time = time.time()
|
|
seconds = "%.3f"% (end_time - start_time)
|
|
if logger:
|
|
logger.info(f"{func.__name__}耗时:{seconds}秒")
|
|
else:
|
|
print(f"{func.__name__}耗时:{seconds}秒")
|
|
return res
|
|
return inner
|
|
return wrapper
|
|
|
|
|
|
def bas64_encode(func):
|
|
"""
|
|
装饰器:Base64加密文本(func返回的文本)
|
|
:param func:
|
|
:return:
|
|
"""
|
|
def inner(*args, **kwargs):
|
|
text = func(*args, **kwargs)
|
|
if isinstance(text, str):
|
|
text = bas64_encode_text(text)
|
|
return text
|
|
return inner
|
|
|
|
|
|
def bas64_decode(func):
|
|
"""
|
|
装饰器:Base64解密文本(func返回的文本)
|
|
:param func:
|
|
:return:
|
|
"""
|
|
def inner(*args, **kwargs):
|
|
text = func(*args, **kwargs)
|
|
if isinstance(text, str):
|
|
text = bas64_decode_text(text)
|
|
return text
|
|
return inner
|
|
|
|
|
|
def decode(crypto=""):
|
|
"""
|
|
解密装饰器:BASE64
|
|
:param crypto: 解密算法名称(忽略大小写)
|
|
"""
|
|
def wrapper(func):
|
|
def inner(*args, **kwargs):
|
|
text = func(*args, **kwargs)
|
|
if isinstance(text, str) or crypto:
|
|
if crypto.lower() == 'base64':
|
|
text = bas64_decode_text(text)
|
|
else:
|
|
text = text
|
|
return text
|
|
return inner
|
|
return wrapper
|
|
|
|
|
|
def encode(crypto=""):
|
|
"""
|
|
解密装饰器:BASE64
|
|
:param crypto: 解密算法名称(忽略大小写)
|
|
"""
|
|
def wrapper(func):
|
|
def inner(*args, **kwargs):
|
|
text = func(*args, **kwargs)
|
|
return text
|
|
return inner
|
|
return wrapper
|
|
|
|
|
|
def envFunction(envs='', execute=True, result=None):
|
|
"""
|
|
环境函数装饰器:根据指导环境与当前环境是否匹配,判断是否执行某个函数
|
|
:param envs:为True时,当前环境与指定的envs匹配时,执行该函数
|
|
: 为False时,当前环境与指定的envs匹配时,不执行该函数
|
|
:param result:指定当该函数被越过时的返回值,默认None
|
|
实例:当环境为production时,才会执行robot_broadcast(),否则相当于在robot_broadcast里直接return
|
|
@envFunction(envs=['production', ], execute=True)
|
|
def robot_broadcast(content=''):
|
|
pass
|
|
|
|
"""
|
|
def wrapper(func):
|
|
@functools.wraps(func)
|
|
def inner(*args, **kwargs):
|
|
environments = []
|
|
if not envs:
|
|
environments = []
|
|
elif isinstance(envs, str):
|
|
environments = [envs, ]
|
|
elif isinstance(envs, (Iterable, )):
|
|
environments = envs
|
|
if settings.PROJECT_ENV in environments and execute:
|
|
return func(*args, **kwargs)
|
|
elif settings.PROJECT_ENV not in environments and not execute:
|
|
return func(*args, **kwargs)
|
|
return result
|
|
return inner
|
|
return wrapper
|
|
|
|
|
|
def exceptionHandler(logger=None, throw=False, result=None, message=None):
|
|
"""
|
|
异常装饰器:用于统一处理捕获的异常
|
|
:param logger: 指定Logger
|
|
:param throw: 继续抛出这个异常
|
|
:param result: 发生异常时的返回值(throw=True时,无效)
|
|
:param message: 错误信息
|
|
:return:
|
|
"""
|
|
def wrapper(func):
|
|
@functools.wraps(func)
|
|
def inner(*args, **kwargs):
|
|
try:
|
|
return func(*args, **kwargs)
|
|
except Exception as e:
|
|
if logger:
|
|
logger.error(traceback.format_exc())
|
|
if message:
|
|
logger.error(message)
|
|
if throw:
|
|
raise e
|
|
return result
|
|
return inner
|
|
return wrapper
|
|
|
|
|
|
class CacheResponse(object):
|
|
def __init__(self,
|
|
timeout=None,
|
|
key_func=None,
|
|
cache=None,
|
|
cache_errors=None):
|
|
if timeout is None:
|
|
self.timeout = extensions_api_settings.DEFAULT_CACHE_RESPONSE_TIMEOUT
|
|
else:
|
|
self.timeout = timeout
|
|
|
|
if key_func is None:
|
|
self.key_func = 'get_cache_key'
|
|
else:
|
|
self.key_func = key_func
|
|
|
|
if cache_errors is None:
|
|
self.cache_errors = extensions_api_settings.DEFAULT_CACHE_ERRORS
|
|
else:
|
|
self.cache_errors = cache_errors
|
|
|
|
self.cache = get_cache(cache or extensions_api_settings.DEFAULT_USE_CACHE)
|
|
|
|
def __call__(self, func):
|
|
this = self
|
|
@functools.wraps(func, assigned=available_attrs(func))
|
|
def inner(self, request, *args, **kwargs):
|
|
return this.process_cache_response(
|
|
view_instance=self,
|
|
view_method=func,
|
|
request=request,
|
|
args=args,
|
|
kwargs=kwargs,
|
|
)
|
|
return inner
|
|
|
|
def process_cache_response(self,
|
|
view_instance,
|
|
view_method,
|
|
request,
|
|
args,
|
|
kwargs):
|
|
key = self.calculate_key(
|
|
view_instance=view_instance,
|
|
view_method=view_method,
|
|
request=request,
|
|
args=args,
|
|
kwargs=kwargs
|
|
)
|
|
is_no_cache = False
|
|
is_no_cache_fun = getattr(view_instance, 'is_no_cache', None)
|
|
if is_no_cache_fun and is_no_cache_fun(request):
|
|
is_no_cache = True
|
|
response = None
|
|
if not is_no_cache:
|
|
response = self.cache.get(key)
|
|
if not response:
|
|
response = view_method(view_instance, request, *args, **kwargs)
|
|
response = view_instance.finalize_response(request, response, *args, **kwargs)
|
|
response.render() # should be rendered, before picklining while storing to cache
|
|
|
|
if not response.status_code >= 400 or self.cache_errors:
|
|
if not is_no_cache:
|
|
if isinstance(response, Response):
|
|
self.cache.set(key, response.data, self.timeout)
|
|
else:
|
|
self.cache.set(key, response, self.timeout)
|
|
handle_refresh_cache_fun = getattr(view_instance, 'handle_refresh_cache', None)
|
|
if handle_refresh_cache_fun:
|
|
handle_refresh_cache_fun(request=request, key=key, cache=self.cache)
|
|
if not isinstance(response, Response):
|
|
response = Response(data=response)
|
|
if not hasattr(response, '_closable_objects'):
|
|
response._closable_objects = []
|
|
return response
|
|
|
|
def calculate_key(self,
|
|
view_instance,
|
|
view_method,
|
|
request,
|
|
args,
|
|
kwargs):
|
|
if isinstance(self.key_func, six.string_types):
|
|
key_func = getattr(view_instance, self.key_func)
|
|
else:
|
|
key_func = self.key_func
|
|
return key_func(
|
|
view_instance=view_instance,
|
|
view_method=view_method,
|
|
request=request,
|
|
args=args,
|
|
kwargs=kwargs,
|
|
)
|
|
|
|
|
|
cache_response = CacheResponse
|
|
|