在实际的工作中我们经常需要定时完成一些操作,比如生成月度销售报表。或者我们需要把一些计算量很大的操作放在夜间执行。这些都可以用定时任务来完成,odoo提供了对定时任务的支持,我们一起来看看。
在本示例中,我们创建一个定时任务,每2分钟执行一次:循环遍历数据库表(scheduler.demo)上的所有记录,每个记录跟踪任务程序运行了多少次。这个示例展示了定时任务如何与数据库操作相结合。
创建模型和字段
创建一个类文件'scheduler_demo.py',内容如下
# -*- coding: utf-8 -*-
from odoo import models, fields, api, exceptions
import logging
from datetime import datetime
_logger = logging.getLogger(__name__)
class scheduler_demo(models.Model):
_name = 'scheduler.demo'
name = fields.Char(required=True)
numberOfUpdates = fields.Integer('Number of updates')
lastModified = fields.Datetime('Last updated')
因为后面要用到日志输出,以及获取系统时间,所以导入python的日志模块和时间模块。
我们创建了scheduler.demo
的新模型,包含三个字段:name的文本字段,是定时任务的名称;numberOfUpdates的整型字段,用于记录任务调用次数;lastModified是时间类型,用于记录任务的最后执行时间。
创建视图
创建xml文件'scheduler_demo.xml',内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="view_scheduler_form">
<field name="name">scheduler.demo.form</field>
<field name="model">scheduler.demo</field>
<field name="arch" type="xml">
<form string="Schedule Form">
<group>
<field name="name"/>
<field name="numberOfUpdates"/>
<field name="lastModified"/>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_scheduler_tree">
<field name="name">scheduler.demo.tree</field>
<field name="model">scheduler.demo</field>
<field name="arch" type="xml">
<tree string="Schedule Tree">
<field name="name"/>
<field name="numberOfUpdates"/>
<field name="lastModified"/>
</tree>
</field>
</record>
</data>
</odoo>
创建了两个视图,from视图和tree视图,方便我们查看记录操作结果。这里都是最基本的视图定义写法,没有什么特别需要说明的。
另外,我们需要让视图显示出来,我这里把菜单挂载在之前的开放学院菜单下,虽然这和开放学院没什么关联。
<field name="lastModified"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="scheduler_demo_list_action">
<field name="name">计划任务Demo</field>
<field name="res_model">scheduler.demo</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="scheduler_demo_menu" name="计划任务Demo"
parent="main_openacademy_menu"/>
<menuitem id="scheduler_demo_list_menu" name="计划任务Demo"
parent="scheduler_demo_menu"
action="scheduler_demo_list_action"/>
</data>
</odoo>
这里定义了一个菜单动作scheduler_demo_list_action
,另外定义了两级菜单。注意定义的顺序,odoo对xml文件是顺序加载的,意味着被引用的id一定要先定义。比如这里必须先定义菜单动作,后定义菜单,因为菜单定义中会引用到菜单动作。
创建定时任务
接下来我们创建核心的定时任务,代码还是写在xml文件'scheduler_demo.xml',我这里放在了act_window定义之前。
<field name="lastModified"/>
</tree>
</field>
</record>
<record id="ir_cron_scheduler_demo_action" model="ir.cron">
<field name="name">Demo scheduler</field>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">2</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'scheduler.demo'" name="model"/>
<field eval="'process_demo_scheduler_queue'" name="function"/>
</record>
<record model="ir.actions.act_window" id="scheduler_demo_list_action">
<field name="name">计划任务Demo</field>
当你安装模块后,将添加一个定时任务:
让我们来分析下定时任务定义的代码,这里的ir.cron模块就是odoo为所有定时任务而专门准备的模型。换句话说往这个表里添加一行数据就是添加了一个定时任务。
name:
定时任务名称
user_id:
执行定时任务的用户,不同的用户是有不同权限的,为了保证能有足够权限执行定时任务,一般这里就是base.user_root
interval_number:
任务执行的频次,和interval_type字段一起决定了任务执行的间隔时间,比如这里为interval_number为2,interval_type为minutes,就是任务每2分钟执行一次。
interval_type:
任务执行频次的单位,可选项有: minutes,hours,days,work_days,weeks,months,意思很好理解,work_days是星期几执行。
numbercall:
循环运行的次数,比如你填10,那么任务执行10次后将不再执行,这里-1代表一直执行下去。
doall:
如果在服务器重启期间错过了执行时机,是否再次补充执行。
model:
任务方法所在模块
function:
任务方法,与model一起决定了任务时机到来时,调用哪个方法执行。
添加python方法
是的,我们还有一个关键的地方,就是任务方法还没有添加,在类文件'scheduler_demo.py'中添加代码:
lastModified = fields.Datetime('Last updated')
def process_demo_scheduler_queue(self):
scheduler_line_ids = self.env['scheduler.demo'].search([])
for scheduler_line in scheduler_line_ids:
_logger.info('line:' + scheduler_line.name)
scheduler_line.numberOfUpdates += 1
scheduler_line.lastModified = datetime.utcnow()
这里代码很简单,首先获取'scheduler.demo'模型中的所有数据行,然后循环操作
-
_logger.info('line:' + scheduler_line.name)
在日志输出当前操作的数据行名称 -
scheduler_line.numberOfUpdates += 1
将执行次数加1 -
scheduler_line.lastModified = datetime.utcnow()
更新最后执行时间。
结论
定时任务是Odoo中的一个强大工具,非常灵活的选项。利用好定时任务,可以帮我们节省大量的手工执行时间。