大数跨境
0
0

Odoo | 如何自定义装饰器?

Odoo | 如何自定义装饰器? AI实践工程院
2022-10-24
1
导读:搞定复杂的数据记录!





Odoo

神州数码云基地

在 Odoo 上的尝试、调研与分享




 本期内容 

 自定义装饰器 


实际开发中我们可能会遇到如下场景:当我们对数据进行新增或修改后,需要记录数据的操作日志到任务表,方便后续追踪记录。


通常的做法是在新增或修改方法执行完后添加对应的操作记录保存到任务表中。


这样虽然可以实现功能,但会在多个方法里重复的写同一段逻辑,且是与业务无关的操作。


这使业务操作与日志记录保存操作耦合在一起,那有没有其它方式了?本文将介绍通过装饰器的方式来更好地实现上述功能。





什么是装饰器 


装饰器本质上是一个Python函数(其实就是闭包)


在特定条件下,为某些函数在不改动函数体的情况下新添加一些功能。


装饰器的返回值也是一个函数对象,装饰器常用于以下场景:插入日志、性能测试、事务处理、缓存、权限校验等。


Odoo中有很多自带的装饰器,比如:


  • onchange装饰器是在监听字段发生改变时自动触发该方法;

  • depends装饰器是在监听字段发生改变,并存储后才触发的装饰器;

  • api.constrains监听的字段创建时(一个或多个),触发该方法;

  • @api.model装饰器表示此时的self仅代表模型本身,不含任何记录信息。当你认为这段代码跟self中的数据无关时就可以使用该装饰器。


以上都是Odoo中提供的装饰器,接下来我们将分享一下如何自定义装饰器。





自定义装饰器  


 简单装饰器函数定义 


简单装饰器函数不带任何参数。


如下设计一个装饰器函数,其功能是能使得被装饰的函数调用结束后,打印出函数运行时间,如下定义了一个装饰器函数cost_time:


def cost_time(func):    def inner():        begin_time = time.perf_counter()        func()        print('函数执行的时间:', time.perf_counter() - begin_time)     return inner


接下来定义一个work函数,打印1-10000,并加上装饰器,代码如下:


@cost_timedef work():    for i in range(10000):        print(i)


运行work函数可以看到的到了函数的执行时间,结果如下所示:



 带参数装饰器函数定义 


有时候我们可能需要在装饰器里面加入参数进行一些判断操作,那么不带参数的装饰器就不能满足我们的要求。


如下设计了一个装饰器,带一个参数控制代码段的执行


def outer(flag):  # step 2    def wrapper(func):  # step 4        def inner(*args, **kwargs):  # stpe 6            if flag:  # step 9                print('before')  # step 10                ret = func(*args, **kwargs)  # step 11  执行原函数                print('after')  # step13             else:                ret = func(*args, **kwargs)                # print('123')                # return ret  # step 14        return inner  # step 7    return wrapper  # step 5


这里当参数为True时,会打印before和after日志,执行如下函数:


@outer(True) def hahaha():    print('执行哈哈哈')


执行结果如下所示:




 项目中的一个案例 


项目里有这样一个需求:上报数据操作后,需要记录上报数据的记录单任务表,方便进行下一步的数据推送工作。


上报数据分为单个上报操作、批量上报操作、全部上报操作。


每个操作都需要记录上报的任务到任务表,页面操作如下图所示:



如果在每个操作里添加保存任务记录,会有大量的重复代码,因此这里提供的解决方案是使用装饰器来统一处理。


装饰器的定义如下所示:


def report(table_name, task_method):    """    上报数据装饰器    """     def method(func):        def make_decorate(*args, **kwargs):            ret_value = func(*args, **kwargs)            if len(ret_value) == 1 and args[0]:                getattr(ret_value[0], task_method)(table_name, [args[0].id])            elif ret_value and args[0]:                getattr(ret_value[1], task_method)(table_name, [args[0].id])                return ret_value[0]            else:                getattr(ret_value[1], task_method)(table_name, ret_value[0])         return make_decorate     return method


上面编写的是带参数的装饰器,table_name代表表名,task_method代表方法名。


此装饰器是在方法执行后执行操作记录保存操作,即后置操作


装饰器定义完毕,那怎么使用装饰器勒?我们只需要在需要执行的方法上面加上装饰器即可,如下所示:


@data_report.report('h3c_order', 'save_h3c_send_task')def save_h3c_project_report(self):    """    保存并上报    """    self.update_time = fields.date.today()    self.data_status = DataStatus.REPORTING.value    self.report_person = self.env.user.name    self.report_time = fields.datetime.now()    return self.go_to_list(), self.env['h3c.send.task']


到这里就给要装饰的方法加上了装饰器,直接此方法可以看到操作记录存入到表中,如下如所示:



以上就是自定义装饰器在Odoo中的一个应用。





有更好的办法或疑问请

⬇欢迎加入社群一起讨论哦⬇

 本期作者 

 高级后端开发工程师 程欢 



更多精彩内容 





了解云基地,就现在!


IT技术哪家

神州数码最在行

行业新星后起之秀

历史虽不长,但实 力 强




【声明】内容源于网络
0
0
AI实践工程院
我们致力于用数字技术重构企业价值,助力企业实现数字化转型升级。
内容 434
粉丝 0
AI实践工程院 我们致力于用数字技术重构企业价值,助力企业实现数字化转型升级。
总阅读397
粉丝0
内容434