扫码阅读
手机扫码阅读

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

280 2023-09-22


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 设置成了"";

  • 3warnings.filterwarnings() 设置警告过滤器,去除一些不必要的告警信息;

  • 4resetlocale 设置国际化;

  • 5根据 syslog 配置参数,以及操作系统类别,设置系统日志的handler

  • 6给 handler 设置 fomatter;

  • 7将设定好的 handler 添加到 root logger(root logger 与各个包层级下衍生 logger 的关系这里不做赘述);

  • 8给 wekzeug 包下的 logger 对象添加 filter;

  • 9根据 log_db 配置参数设定 postgresqHandler ,确定是否将日志入库,以及 log_db_level 确定入库日志的级别

  • 10logging_configurations 设定特定几个包名下logger的配置。

logger的调用

通过logging.logging.getLogger(_name_)调用前包层级的logger 对象,logging.logging.getLogger() 则返回root logger对象。

本期关于Odoo的ORM和日志就聊到这里,下一期我们会继续聊一下Odoo的异常和流程引擎,感兴趣的小伙伴记得关注我~

Odoo框架源码解读干货

用心奉上,欢迎交流~

你有更好思路或疑问

快来加入社群一起讨论哦⬇


本期作者

黄华信

原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247519281&idx=1&sn=23f8e86713b80a23ea1eb53b5041e957&chksm=c02fb797f7583e81e12e0f76b8e904fd9f7b9a8a4225ce252eed1c18965aaa89bb7d6421ad74#rd