第十一章 数据文件

篇别:第一篇 基础知识

本章学习目标

  • 能编写 XML 数据文件recordfunctiondelete)并理解 加载顺序ref 的影响。
  • 能维护 ir.model.access.csvCSV 数据 并处理 编码与列规范
  • 能根据场景选择 noupdate 策略,并解释升级时「改了 XML 却不生效」的原因。
  • 能区分 datademo,并在生产、CI、培训环境中正确启用演示数据。

导读:数据文件在模块中的角色

模块不仅包含 Python 与视图,还通过 XML/CSV/YML(少见) 向数据库注入 元数据与种子数据:序列、权限、菜单、默认配置等。安装与升级时,框架按 __manifest__.pydata / demo 列表顺序 加载这些文件。理解 ir.model.data(外部 ID)noupdate 是避免「环境不一致」的关键(详见第六章)。


11.1 XML 数据文件

11.1.1 知识要点

元素 作用
<record> 创建或更新一条业务记录;id 生成 XML ID
<field> 字段值;可用 eval 执行 Python 表达式
<function> 调用模型方法,适合复杂初始化
<delete> idsearch 删除(生产慎用

常用 field 写法

  • 文本:<field name="name">值</field>
  • 引用:<field name="model_id" ref="model_library_book"/>
  • 布尔:<field name="active" eval="True"/>
  • 多对多:<field name="groups_id" eval="[(4, ref('base.group_user'))]"/>
  • 一对多子表:嵌套 <record> 或使用 function 创建

11.1.2 案例

案例 A:序列

<record id="seq_library_book" model="ir.sequence">
  <field name="name">图书编号</field>
  <field name="code">library.book</field>
  <field name="implementation">standard</field>
  <field name="prefix">B</field>
  <field name="padding">5</field>
  <field name="number_next">1</field>
</record>

案例 B:在模型上调用 function

<function model="library.book" name="action_rebuild_default_codes">
  <value eval="[]"/>
</function>

方法需 @api.model 且接受参数列表;具体签名以实现为准。

案例 C:按 domain 删除(仅开发/迁移)

<delete model="library.book" search="[('active','=',False)]"/>

风险:误删生产数据;务必 先在副本验证,并考虑 备份

11.1.3 截图占位

图 11-1 `__manifest__.py` 中 data 列表顺序

图 11-1b 技术菜单中某条 XML 导入生成的记录

11.1.4 本节练习

  1. 实操:用 XML 创建 3 条 默认图书记录(nameisbn),并保证第二次升级 不重复插入(提示:固定 idrecord 会更新同一条)。
  2. 简答:同一文件内后面的 record 能否 ref 前面定义的 id?跨文件呢?
  3. 判断<delete search="..."/> 在每次 -u 都会执行删除。( )

参考答案提示:2. 同模块同次加载顺序内可以;跨文件取决于 manifest 中文件顺序。3. 对,每次升级若仍匹配 domain 会删,极危险。


11.2 CSV 数据文件

11.2.1 知识要点

  • 首行:字段名,须与模型 完全一致(或 CSV 约定列)。
  • idmodule.name 形式定义 外部 ID,如 my_library.access_book_user
  • model_id:id:id 后缀:指向另一条 CSV/XML 行的 外部 id,加载器自动解析为整数。
  • 编码UTF-8(无 BOM 或统一约定);Excel 另存需注意。
  • 换行与引号:字段内含逗号时需正确引号包裹。

11.2.2 案例

案例 A:访问权限 CSV

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_library_book_user,library.book.user,model_library_book,base.group_user,1,1,1,0

案例 B:从界面导出再改

设置 → 技术 → 模型访问权限 → 导出 → 增删行 → 放回模块 security/ → 升级。

11.2.3 截图占位

图 11-2 CSV 用 UTF-8 在编辑器中打开

图 11-2b 导入失败时日志中的列名错误提示

11.2.4 本节练习

  1. 简答:CSV 加载失败常见 5 种原因?
  2. 实操:故意删掉 CSV 首行一列名,记录完整报错。
  3. 简答:为何 ir.model.access 常用 CSV 而很少用纯 XML?

参考答案提示:1. 编码、列名、ref 不存在、重复 id、布尔/整数格式错误。3. 行多、 diff 清晰、团队习惯。


11.3 data 与 noupdate

11.3.1 知识要点

  • <odoo noupdate="1">:块内通过 XML ID 匹配到的记录,在 模块升级 时可能 不再用文件内容覆盖 已有字段(用户自定义保留)。
  • noupdate="0" 或默认:升级时 同步 XML 中的字段值(仍受字段与模型逻辑约束)。
  • 痛点:你以为改了 XML,升级后界面没变 → 可能是 noupdate用户已改库内记录
  • 破解(慎用):删 ir.model.data 对应行、改 XML id、用迁移脚本 SQL 更新。

11.3.2 案例

<odoo noupdate="1">
  <record id="library_default_max_days" model="ir.config_parameter">
    <field name="key">library.default_max_days</field>
    <field name="value">14</field>
  </record>
</odoo>

说明:用系统参数演示 noupdate;业务上也可在 res.config.settings 的扩展字段中写 config_parameter(见第八章 8.13)。

11.3.3 截图占位

图 11-3 升级日志中与 noupdate 相关输出

11.3.4 本节练习

  1. 判断noupdate=1 时永远不能再改该记录。( )
  2. 实操:对某 noupdate=1 记录在界面改一个字段,再 -u 模块,观察该字段是否被 XML 改回。
  3. 简答:哪些数据适合 noupdate=1?哪些必须 0

参考答案提示:1. 错。3. 用户可配默认适合 1;法规强制结构适合 0 或由迁移脚本改。


11.4 演示数据(新增)

11.4.1 知识要点

  • demo__manifest__.py 中独立列表,常在 创建数据库勾选「加载演示数据」 时安装;生产库 勿依赖
  • 趋势:演示数据 默认不进入生产;培训环境可单独建库启用。
  • CI:测试若依赖 demo 数据,需在流水线中 显式安装带 demo 的库在测试里 create

11.4.2 案例

# __manifest__.py
'demo': [
    'demo/library_demo.xml',
],
<!-- demo/library_demo.xml -->
<odoo noupdate="1">
  <record id="demo_book_1" model="library.book">
    <field name="name">演示图书一</field>
    <field name="isbn">DEMO-001</field>
  </record>
</odoo>

noupdate 可防止演示库被升级反复重置(按需)。

11.4.3 截图占位

图 11-4 数据库管理器:演示数据勾选

11.4.4 本节练习

  1. 简答:为何生产库不建议加载 demo?
  2. 情景:销售演示前需要「像真的一样」的数据,如何既不污染生产又不手写 XML?

参考答案提示:2. 独立演示库、neutralize 副本、或导入专用 SQL/模块。


11.5 数据加载调试清单

现象 检查项
ParseError XML 语法、标签闭合、特殊字符转义
External ID not found refdepends、文件顺序
升级无变化 noupdate、是否改错模块/数据库
CSV 乱码 UTF-8、Excel 保存格式

11.5.1 截图占位

图 11-5 终端升级失败 traceback 片段

11.5.2 本节练习

  1. 实操:用 -u my_module --log-level=debug 截取一段数据加载日志并标注文件名顺序。

本章综合练习

  1. 编写 <function>:升级时为所有 default_code 为空 的图书调用模型方法生成编码(方法内用序列)。
  2. 风险分析<delete model="library.loan" search="[('state','=','draft')]"/> 在生产使用的 前置条件(备份、停机、验证 SQL 条数等)。
  3. 设计:同一配置项既要 首次安装默认值 又要 允许用户永久覆盖,如何用 noupdate + 单独 config_parameter 表达?
  4. 拓展:阅读官方 Manifest 文档中关于 data / post_load 的说明,一句话记录差异。

本章对应白皮书目录:第十一章 数据文件。