错误抛出

前端时间在生产环境上线了一个定时任务,目的是采集客户信息,以用来分析客户数据。2022-05-30 系统告警出现了错误。下面是错误信息:

2022-05-30 14:40:46,332 76 ERROR momo_prod odoo.addons.base.models.ir_cron: Call from cron Partner信息采集定时任务 for server action #417 failed in Job #17
Traceback (most recent call last):File '/opt/momo/odoo/api.py', line 793, in getreturn field_cache[record._ids[0]]
KeyError: 12
During handling of the above exception, another exception occurred:
Traceback (most recent call last):File '/opt/momo/odoo/fields.py', line 972, in __get__value = env.cache.get(record, self)File '/opt/momo/odoo/api.py', line 796, in getraise CacheMiss(record, field)
odoo.exceptions.CacheMiss: 'res.partner(75432,).group_id'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):File '/opt/momo/odoo/addons/base/models/ir_cron.py', line 110, in _callbackself.env['ir.actions.server'].browse(server_action_id).run()File '/opt/momo/odoo/addons/base/models/ir_actions.py', line 632, in runres = runner(run_self, eval_context=eval_context)File '/opt/momo/odoo/addons/base/models/ir_actions.py', line 501, in _run_action_code_multisafe_eval(self.code.strip(), eval_context, mode='exec', nocopy=True)  # nocopy allows to return 'action'File '/opt/momo/odoo/tools/safe_eval.py', line 330, in safe_evalreturn unsafe_eval(c, globals_dict, locals_dict)File '', line 1, in <module>File '/opt/momo/addons/momo_cron/models/cron_partner.py', line 199, in _action_cron_do_collectioncollection_item.handle_record()File '/opt/momo/addons/momo_cron/models/cron_partner.py', line 119, in handle_collectionparent_name = partner_res.group_id.nameFile '/opt/momo/odoo/fields.py', line 2485, in __get__return super().__get__(records, owner)File '/opt/sps/odoo/fields.py', line 1004, in __get___('(Record: %s, User: %s)') % (record, env.uid),
odoo.exceptions.MissingError: Record does not exist or has been deleted.
(Record: res.partner(75432,), User: 1)

简单分析

定位到报错代码位置(line 119):

parent_name = partner_res.group_id.name

再看最后的错误信息:

odoo.exceptions.MissingError: Record does not exist or has been deleted.
(Record: res.partner(75432,), User: 1)

结合可知,错误并不是因为字段  group_id 可能没有值导致的问题,而是因为记录 partner_res 不存在或已删除导致的。

但这不对呀,我是判断了 partner_res 是否存在的:

    partner_res = res_partner_obj.browse(self.partner_id)if partner_res:parent_name = partner_res.group_id.nameelse:parent_name = ""

如果 partner_res 不存在,就不应该走 partner_res.group_id.name ,更不应该报错。打个断点跟一下。

Debug

打上断点跟了一下不咋滴,这一跟简直跟出了一条惊天大案!

问题定位到了这句看起来非常普通的代码上:

partner_res = res_partner_obj.browse(self.partner_id)

断点过程发现 self.partner_id 是有值的,但数据库中确实不存在 id 为现 75432 的记录。怀疑问题出现在browse方法上,browse方法可能压根儿没走数据库。为了验证这个问题,我将问题代码简单抽出来复现一下。

问题复现

TIP: 已知在数据库中,表res_partner中不存在 id 为 999999 的记录,通过使用 browse 查找记录。

def match_record_by_browse(self):"""演示 browse 查询记录集:return:"""browse_result = self.env["res.partner"].browse(999999)print("browse_result", browse_result)if browse_result:print("browse_result yes")else:print("browse_result no")

终端输出

browse_result res.partner(999999,)
browse_result yes

可以看到数据库中,没有 id 为 999999 的记录,依然输出了 res.partner(999999,) 。

browse() API

查看下browse源码:

    ## Instance creation## An instance represents an ordered collection of records in a given# execution environment. The instance object refers to the environment, and# the records themselves are represented by their cache dictionary. The 'id'# of each record is found in its corresponding cache dictionary.## This design has the following advantages:#  - cache access is direct and thus fast;#  - one can consider records without an 'id' (see new records);#  - the global cache is only an index to "resolve" a record 'id'.#
​@classmethoddef _browse(cls, env, ids, prefetch_ids):""" Create a recordset instance.
​:param env: an environment:param ids: a tuple of record ids:param prefetch_ids: a collection of record ids (for prefetching)"""records = object.__new__(cls)records.env = envrecords._ids = idsrecords._prefetch_ids = prefetch_idsreturn records
​def browse(self, ids=None):""" browse([ids]) -> records
​Returns a recordset for the ids provided as parameter in the currentenvironment.
​.. code-block:: python
​self.browse([7, 18, 12])res.partner(7, 18, 12)
​:param ids: id(s):type ids: int or list(int) or None:return: recordset"""if not ids:ids = ()elif ids.__class__ in IdType:ids = (ids,)else:ids = tuple(ids)return self._browse(self.env, ids, ids)

王德发!browse方法真的没有访问数据库,只是将提供的 id 包装成了当前环境的实例。目的是为了快速读取数据。

实例表示给定执行环境中的有序记录集合。实例对象引用环境,而记录本身由它们的缓存字典表示。每条记录的“id”都可以在其对应的缓存字典中找到。

这种设计具有以下优点:

  • 缓存访问是直接的,因此速度很快。

  • 可以考虑没有“id”的记录。

  • 全局缓存只是“解析”记录“id”的索引。

这么来看,browse方法并不关心传入的 id 在相关表中是不是存在。它仅仅是为了将给定的 id 包装成ORM可用的实例。

问题解决

这是一个browse方法使用的问题。将browse方法替换为search方法,通过search方法访问数据库,查找是否真正存在即可解决此问题。

partner_res = res_partner_obj.search([("id", "=", self.partner_id)])

【ODOO】来了解一下browse方法相关推荐

  1. 如何在Odoo创建新数据的时候添加自己的方法 - 重写create方法

    相信有一些小伙伴在使用odoo的时候,需要在创建数据的同时给一些数据自动赋值,虽然在使用onchange方法也基本可以实现需求,但是总是在一些特色的想法的onchange是不能满足需求的. odoo自 ...

  2. odoo10参考系列--ORM API 二(新旧API兼容性、模型参考和方法修饰符)

    新API与旧API的兼容性 现在的Odoo是从就的(不规律的)API过渡来的,它可能需要从一个手动桥接到另一个手动桥接: RPC层(XML-RPC和RPC)是在旧的API的形式表达,表达的纯粹的方法在 ...

  3. odoo中的ORM操作

    ORM方法简介 OpenERP的关键组件, ORM是一个完整的对象关系映射层,是开发人员不必编写基本的SQL管道. 业务对象被声明继承字models.Models的python类. 这让业务对象在OR ...

  4. odoo13中的模型类中的方法函数ORM方法以及模型方法的装饰器

    1.模型类的方法函数(ORM方法) 方法 解释 create方法 记录创建方法.创建记录的orm函数. 页面新建点击保存时触发调用. 返回值为创建成功的记录集. write方法 记录更新方法.修改记录 ...

  5. odoo 的字段。orm对象

    OpenERP ORM 对象方法列表 OpenERP对象支持的字段类型有,基础类型:char, text, boolean, integer, float, date, time, datetime, ...

  6. Odoo ERP 14 客户关系管理

    CRM 客户关系管理是为任何公司提供商业机会和利润的业务运营中不可避免的一部分.吸引新客户并与现有客户保持良好的关系将提高公司利润.Odoo平台为这些公司提供了先进的管理方面和工具,可同潜在客户和忠实 ...

  7. odoo 14 手册 财务管理 应收应付 总账 报表

    任何公司运营的财务管理都将更加棘手,因为管理涉及的参数众多,因为它围绕整个公司运营.公司会计和财务方面的有效管理工具将为财务经理中的会计师减轻负担.Odoo 为用户提供了卓越.高效.可靠的公司财务和账 ...

  8. odoo model注意事项-2(个人总结,不喜勿喷)

    11.在__mainfest__.py中,要在depends中写上所依赖的模块名,在data中写上用到视图文件的名字,比如在views中有work.xml文件,在data中写上'views/work. ...

  9. AS3 CookBook学习整理(十七)

    1. 下载文件 使用flash.net.FileReference对象的download(urlRequest, aliasName)方法 download()方法最好在try...catch语句中执 ...

最新文章

  1. Java项目:学生信息管理系统(java+SSM+JSP+layui+maven+mysql)
  2. com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'user'
  3. php如何检测数组是否存在,php – 如何检查数组元素是否存在?
  4. MSSql-1内部数据库版本号
  5. 11旋转编码器原理图_雷恩PRECILEC I9H系列增量式编码器
  6. PHP获取IP地址的方法,防止伪造IP地址注入攻击
  7. Protobuffer教程
  8. 实时搜索专家Krzana正式进军金融大数据市场
  9. vue 挂载点 实例 模板
  10. 10个最佳的网站和App开发工具
  11. intellij idea 和 maven的自己的理解和安装配置
  12. Ubuntu18.04版本安装ssh及连接ssh的常见问题
  13. 电机专题2:直流有刷电机工作原理
  14. Debian 挂载ISO镜像软件源
  15. EXCEL如何快速拆分合并单元格数据
  16. 幼儿园计算机基础知识培训总结,幼儿园园本培训工作总结
  17. 《设计模式之禅(第三版)》 摘录篇-------依赖倒置原则
  18. 汽车销售管理系统 c语言版 课程设计,汽车销售管理系统C语言版.doc
  19. 优秀是一种习惯:说一说你身边在世界名校读书的人
  20. powerdesigner设置自动递增

热门文章

  1. vue 中利用canvas 给pdf文件加水印---详细教程(附上完整代码)
  2. 自定义加密算法打造不死网马
  3. Mybatis 中 selectKey的用法
  4. Android中Bitmap按比例放大
  5. win10自带 微软输入法打开自学习功能
  6. webstorm 激活破解
  7. [附源码]Nodejs计算机毕业设计面向大学生的党建管理系统Express(程序+LW)
  8. hide show toggle
  9. 利用类接口技术完成排序
  10. Swagger-springFox3.0使用教程