You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Odoo 17中创建插件卸载后数据仍保留的字段

Odoo 字段持久化需求:ORM正常使用但卸载插件后保留数据

需求说明

  • 希望Odoo ORM能像普通字段一样处理自定义字段,但不控制数据库列
  • 此前将模型扩展打包为插件,卸载时Odoo会删除插件定义的字段(含数据库列及对应数据),不符合业务需求
  • 核心目标:字段在UI和ORM中正常工作,卸载插件后数据完整保留,实现系统优雅降级

当前实现方式

绕过Odoo常规fields.X声明,在_auto_init()方法中动态创建字段:

# @api.model  # Odoo 17已弃用,可移除
def _auto_init(self):
    res = super()._auto_init()   

    # 幂等创建数据库列,确保列存在
    self._cr.execute("ALTER TABLE res_partner ADD COLUMN IF NOT EXISTS x_customer_flag boolean")

    # 仅当字段未注册时,创建ir.model.fields记录
    model = self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1)
    if not self.env['ir.model.fields'].search([('model_id', '=', model.id), ('name', '=', 'x_customer_flag')]):
        self.env['ir.model.fields'].create({
            'name': 'x_customer_flag',
            'model_id': model.id,
            'field_description': 'Customer is banned from store',
            'ttype': 'boolean',
            'state': 'manual',     # 预期可防止更新时自动删除字段
            'manual': True         
        })

    return res

卸载插件时,仅删除ir.model.fields中的字段记录,保留数据库列及数据。

理想简化方案

希望采用常规fields.Boolean()声明简化代码,同时保持数据持久化,理想代码示例:

class GisResPartnerExtension(models.Model):
    _inherit = 'res.partner'

    x_customer_flag = fields.Boolean(string="Customer is banned", manual=True) # 注:manual=True为虚构参数

    def _auto_init(self):
        res = super()._auto_init()
        # 按需幂等创建数据库列(非破坏性)
        return res

但manual=True并非真实可用参数,且字段自带的manual标识作用不明确,因此寻求更优实现方式。


内容的提问来源于stack exchange,提问作者wz2b

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:34:56