Odoo丨Odoo框架源码研读二:ORM框架与日志
而Odoo在实际开发的大多数场景都是基于它的ORM框架进行的,所以本期我们将带来Odoo框架源码的第二期内容——ORM和日志。
*ORM*
Odoo是通过Controller控制器,来控制前后台的交互。上一期我们详细的介绍了如何让请求顺利到达Controller控制器。
那么当请求到达Controller后,又如何来实现后端的业务逻辑呢?这就不得不提到Odoo一个非常强大的类——Environment。
Environment:
通过_loca属性,Environment可以直接管理线程中的environments上下文状态,并且包装了ORM相关四个属性:
- cr:当前数据库游标对象,通过self.env.cr(sql),可以直接执行SQL语句进行数据的CRUD;
- uid:当前登陆用户ID,通过self.env.uid获取当前登陆用户ID;
- context:当前上下文字典,通过self.env.context,我们可以缓存前后端的数据用来交互;
- su:切换超级用户模式,通过它我们可以越过model_access 权限的校验,直接操作数据。
而且Environment还提供了Model name和Model之间的映射,通过self.env[ModelName] 就可以直接调用Model的API ,非常强大。
现在,再回头看Controller中的方法,可以看到,通过request.env[model]可以直接获取对应的Model对象,然后直接调用Model的方法。
Model
Odoo中一切都是基于Model编程。即使是前端的menu、action、view,都是也都有对应 Model,和业务数据无异。
创建一个Model ,然后通过简单的视图配置,那么这个Model对应的CRUD基础功能就已经实现,这些都归功于Odoo对于Model的抽象。
Odoo中的model分为三类:AbstractModel、Model、TransientModel;
- Model:⽤于常规的数据库持久化模型;
- TransientModel:⽤于存储在数据库中的临时数据,但会经常⾃动清理;
- AbstractModel:⽤于要由多个继承模型共享的抽象超类。
继承关系如下图 ⬇
从源码中可以看出AbstractModel 是Model 和TransientModel的父类。而这个三者的区别也主要在_auto、_register、_abstract、_transient这四个属性上。
由此可以AbstractModel是抽象类,不会在数据库创建表,Model和TransientModel 不是抽象类,会在数据库建表,但TransientModel建的是临时表,数据会被系统定期清除,这个可以在系统中设置清除频率。
由于这种特性的不同,三个Model的用途也不相同。
TransientModel由于存临时表的特性,多用来做wizard向导视图,存储临时缓存数据;
Model多用于做业务的主要Model,AbstractModel多用来抽象做父类,由于不创建表的特性,有时也会用来做向导视图。
新模块中的Model,根据功能需要去继承这三个类,由于这三个父类中丰富的API方法,新建 Model在创建完字段后,功能就已经基本完善,如果有定制化的逻辑,只需要重写父类的方法就可以了。
Field
Model中的Field不是Python的基础类型,而是继承Odoo封装的Field类。
因此,在Model字段赋值的时候,和基础类型字段不同,会调用Field中的API方法,这是容易踩坑的地方。
*日志*
Odoo的日志是在Python的logging基础模块之上,做了定制化的封装和配置。这部份代码主要在odoo/netsvc.py文件中。
Odoo定义了自己的Filter对象、Formatter对象、以及Handler对象。
- Handler对象:日志处理器,对传入的日志进行处理。比如PostgreSQLHandler就是把日志存入数据库;
- Formatter对象: 日志格式器,对日志内容进行格式化;
- Filter对象:日志过滤器,可以实现复杂的过滤,截取需要的日志内容。
配置参数
1)项目启动的时候,配置管理器configmanager初始化,这个时候会去初始化默认的系统配置,包括日志模块。
2)随后,配置管理器会去加载配置文件odoo.conf中的自定义配置覆盖原先的默认配置。
3)最后,处理完配置加载,Odoo会调用日志初始化代码,根据最终的日志配置去设定相关的logger对象。
上图即为Odoo日志的默认配置。
初始化
初始化过程:
- 1)设定日志初始化标志 _logger_init ,保证Odoo只会初始化一次logger对象;
- 2)设定 logRecordFactory ,在日志信息中添加定制化参数信息,这里是将 perf_info 设置成了"";
- 3)warnings.filterwarnings() 设置警告过滤器,去除一些不必要的告警信息;
- 4)resetlocale 设置国际化;
- 5)根据 syslog 配置参数,以及操作系统类别,设置系统日志的handler;
- 6)给 handler 设置 fomatter;
- 7)将设定好的 handler 添加到 root logger(root logger 与各个包层级下衍生 logger 的关系这里不做赘述);
- 8)给 wekzeug 包下的 logger 对象添加 filter;
- 9)根据 log_db 配置参数设定 postgresqHandler ,确定是否将日志入库,以及 log_db_level 确定入库日志的级别;
- 10)logging_configurations 设定特定几个包名下logger的配置。
logger的调用
通过logging.logging.getLogger(name)调用前包层级的logger 对象,logging.logging.getLogger() 则返回root logger对象。
本期关于Odoo的ORM和日志就聊到这里,下一期我们会继续聊一下Odoo的异常和流程引擎,感兴趣的小伙伴记得关注我~