Odoo丨Odoo框架源码研读二:ORM框架与日志

Odoo
神州数码云基地
在 Odoo 上的尝试、调研与分享
本期内容
Odoo源码研读:ORM与日志
上一期我们带来了关于Odoo框架源码第一期内容(传动门➡《Odoo框架源码研读一:前后端交互》),让大家对Odoo整体结构和前后端交互有了更深刻的了解。
而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的异常和流程引擎,感兴趣的小伙伴记得关注我~
Odoo框架源码解读干货
用心奉上,欢迎交流~
你有更好思路或疑问
快来加入社群一起讨论哦⬇
本期作者
黄华信

