Odoo 如何用 populate 命令基于现有记录批量复制数据生成测试库
【免费下载链接】odooOdoo. Open Source Apps To Grow Your Business.项目地址: https://gitcode.com/GitHub_Trending/od/odoo
如果你手上已有一个带少量真实数据的 Odoo 数据库,想快速得到一份数据量放大若干个版本的测试/演示库,而不必手工录入,Odoo 内置的populate命令就是为此设计的:它以数据库中现有记录为模板做批量复制(duplication),同时维护外键引用一致性、处理唯一约束字段,并优化大批量插入性能。实现入口在 odoo/cli/populate.py,核心 SQL 逻辑在 odoo/tools/populate.py。
本文适用的前提是:
- 你可以访问 Odoo 源码树(使用其中的 odoo-bin 启动器);
- 目标数据库已经初始化完成,且待放大的模型里至少已有部分记录(空表没有模板可复制,会被直接跳过);
-d/--database只能指定一个数据库,命令检测到多个数据库时直接退出并报错:-d/--database/db_name has multiple database, please provide a single one。
基本命令与三个参数
populate是odoo-bin的一个子命令,参数定义在 odoo/cli/populate.py 中,共三个:
| 参数 | 默认值 | 作用 |
|---|---|---|
--factors | 10000 | 每个模型的复制倍数。可以传一个值,也可以按模型顺序传逗号分隔的多个值;最后一个值会传递给其余未单独指定的模型 |
--models | res.partner,product.template,account.move,sale.order,crm.lead,stock.picking,project.task | 要放大的模型列表(逗号分隔) |
--sep | _ | char/text 字段变化时追加的单字符分隔符(必须是单个 Unicode 字符,否则抛ValueError: Separator must be a single Unicode character.) |
factor的语义在帮助文本里写得很明确:factor 为 3 表示该模型的记录被复制 3 份,最终达到原有数据量的 4 倍(3 + 原始 1 = 4x)。命令内部会自动追加--no-http,即不会拉起 HTTP 服务。
最短的完整命令:
./odoo-bin populate -d my_test_db --models res.partner,product.template --factors 3,10 --sep _这条命令的含义:res.partner复制 3 份(变成 4x),product.template复制 10 份(变成 11x),char/text 字段用_作为变化后缀。
如果不关心默认模型列表,也可以只给一个 factor,它会被所有模型共用:
./odoo-bin populate -d my_test_db --factors 5此时模型列表和 factor 都取默认值(7 个默认模型、每个 factor 10000)。默认 factor 数值很大,只是用来满足 demo 场景的量级需求;如果你的库较小,请按上例显式给一个能接受的倍数。
命令实际做了什么
odoo/tools/populate.py 的模块文档说明了整个复制策略,理解它有助于判断结果是否符合预期:
- 引用完整性:Many2one 字段会被重新映射到对应的副本记录;One2many 通过反向 Many2one 隐式完成;Many2many 通过复制关系表完成。这样复制出来的销售订单仍指向复制出来的客户、订单行等,而不是全部指向同一批原始记录。
- 字段变化:char/text 字段会被追加变化后缀(即
--sep字符)以绕开唯一约束、并让name_search检索有区分度;date/datetime 字段会在一个时间窗口内分布开(硬上限是最近 4 年,避免复制记录日期过早);html 字段为了简单不做变化,直接原样复制。 - 性能优化:插入前临时删除目标表上的普通索引(主键索引和唯一索引保留,以维持约束),插入后按原定义恢复;同时用
SET session_replication_role TO replica关闭外键检查。 - 依赖顺序:带
_inherits的模型会先复制被委托的模型;X2many 关系另一端的模型即使没出现在--models里,也会继承当前模型的 factor 一并被复制(例如防止出现"有订单但没有订单行"的脏数据)。 - 序列修正:复制完成后用
SETVAL把对应表的 id 序列推进到新的最大 id。
执行与结果验证
运行后,关注日志中这几条(均来自 odoo/tools/populate.py 与 odoo/cli/populate.py 实际输出的日志语句):
Populating model <模型名> <N> times...:开始处理某个模型,N 即该模型的 factor;Dropping indexes on table <表名>.../Adding indexes back on table <表名>...:索引临时移除与恢复;- 结束时输出
Populated models [<模型列表>] (total: X.XXXs):表示全部完成并给出总耗时。
判断结果是否如预期,可以用--factors帮助文本给出的量级关系核对:某个模型的最终记录数应为「原始记录数 × (factor + 1)」。例如对res.partner使用 factor 3,命令前后各统计一次该表行数,应为 4 倍关系;char/text 唯一字段的副本会带上_后缀,可顺带抽查确认。
限制与异常现象
以下行为都在源码中有明确定义,遇到时不必视为故障:
- 权限不足时的降级:如果当前 pg_role 没有权限执行
SET session_replication_role TO replica,命令会回滚事务、跳过关闭外键检查这一优化后重试,并打印警告日志:Cannot ignore Fkey constraints during insertion due to insufficient privileges for current pg_role. ... The bulk insertion will be vastly slower than anticipated.——命令继续执行,只是明显变慢。 - 空模型被跳过:模型表里没有任何记录时(
has_records检查不通过),该模型不复制,因为没有模板。POS 性能测试里的注释也印证了这一点:The product.template model must contain at least one record before it can be populated. - transient 与 abstract 模型被过滤:即使写进了
--models,也会被自动剔除。 - 日期窗口:date/datetime 的分布范围被限制在最近 4 年内(
MIN_DATETIME/MAX_DATETIME常量),不会把复制记录的时间推到更早。 - 可重入:命令执行前会先对已有行的 char/text 字段做一轮更新(
UPDATE ... ROW(...)),允许对同一数据库重复运行 populate 而不因重复的后缀逻辑产生混乱。
可选:在 Python/测试代码中直接调用
Populate.populate是类方法,签名见 odoo/cli/populate.py:populate(env, modelname_factors: dict[str, int], separator_code: int)。addons/point_of_sale/tests/test_performances.py 展示了典型用法——按"目标总量 ÷ 现有量 − 1"算出 factor:
from odoo.cli.populate import Populate before_count = self.env[model_name].search_count([]) if not before_count: return False populate_count = round(total_count / before_count) - 1 Populate.populate(self.env, {model_name: populate_count}, 1)注意第三个参数separator_code是传给ord()后的字符码值(CLI 里由ord(opt.separator)得到);上面的1是该测试文件中使用的示例取值。如果你的测试目标模型必须至少存在一条记录(见上文空模型限制),先判断before_count再调用。
如果你的场景只是"把现有数据库放大 N 倍做压测或演示",主路径就是开头的单条./odoo-bin populate -d <库名>命令;--models、--factors、--sep三个参数足以覆盖文档中说明的全部可控行为。
【免费下载链接】odooOdoo. Open Source Apps To Grow Your Business.项目地址: https://gitcode.com/GitHub_Trending/od/odoo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考