先说结论
很多实施顾问会把“项目模板”理解成:
- 找一个做好的项目
- 复制一份
- 改下名字就开工
但 /home/ubuntu/odoo-temp/addons/project/models/project_project.py 和 project_task.py 的实现说明,官方想做的远不止“复制记录”。
模板创建项目时,至少同时处理这几件事:
- 项目日期要不要按今天重新平移
- 哪些字段可以通过
default_上下文覆盖 - 哪些字段绝不能从模板照搬
- 项目角色如何在新项目中分派到具体用户
- 项目内的任务结构怎样跟着复制过去
所以项目模板的本质不是“旧项目复印件”,而是 一个可实例化的项目蓝图。
第一层:从模板建项目,不是简单 copy,而是有专门入口
project.project.action_create_from_template() 是核心入口。
这个名字本身就值得注意:
- 不是让用户随便点“duplicate”
- 而是明确区分“从模板创建”
这意味着在官方设计里,模板实例化是一种单独业务动作,不等于普通复制。
它会带上:
copy_from_template=Truecopy_from_project_template=True
这些上下文标记就是在告诉底层:
现在不是做一份普通副本,而是在把模板落地成真实项目。
第二层:为什么项目日期会自动平移
在 action_create_from_template() 里,如果模板同时有:
date_startdate
那么新项目在没显式传日期时,会:
- 把新的
date_start设为今天 - 再按模板原本的起止间隔,推出新的截止日期
这看起来只是小细节,但其实很重要。
因为项目模板真正复制的,不该是“2025 年 11 月到 12 月”这种历史日期,而应该是:
- 原有工期结构
- 但落到新的现实时间轴上
这就是模板思维和普通复制思维最大的区别之一:
- 普通复制保留原值
- 模板实例化保留相对关系
第三层:为什么 Odoo 要做 whitelist 和 blacklist
项目模板里有两个方法很关键:
_get_template_default_context_whitelist()_get_template_field_blacklist()
目前官方给项目模板开放的默认上下文白名单很克制,比如:
allow_milestones
而黑名单至少包含:
partner_id
这套设计背后的思路非常成熟:
白名单解决“哪些值允许创建时覆写”
也就是模板可以被实例化时安全替换的字段。
黑名单解决“哪些值绝不能机械继承”
partner_id 就是典型例子。
因为模板只是蓝图,客户通常属于具体项目,而不是模板本身的固有属性。
如果把模板客户直接复印到所有新项目,业务上几乎一定出错。
第四层:为什么项目模板不只复制项目本体,还要复制任务骨架
在 map_tasks() 和相关复制逻辑里,Odoo 会把旧项目下的顶级任务找出来,再把任务树复制到新项目。
这里有两个很重要的点:
1. 顶级任务先复制,子任务跟着结构复制
这保证了任务树骨架能在新项目里重建。
2. 复制时会保留某些结构语义,而不是盲目生成一堆散卡片
这也是为什么项目模板适合做标准实施包、标准交付流程,而不是只适合做“数据备份副本”。
第五层:角色映射才是模板落地很有价值的一步
action_create_from_template() 里还有一段很实用的逻辑:
- 如果传入
role_to_users_mapping - 就遍历新项目下的任务
- 找出任务上的
role_ids - 把映射到该角色的用户补进
user_ids - 最后再把
project.task.role_ids清掉
这段逻辑说明官方非常清楚模板的真实用途:
模板里保留的是“需要什么角色”,实例化时再决定“由谁来做”。
这比直接在模板里写死负责人高级得多。
因为模板负责人往往不可能长期稳定:
- 今天这个项目经理离职了
- 下个地区由另一组交付
- 同一种模板在不同团队用法不同
角色映射就很好地把“组织能力模板”和“具体人员分配”分开了。
第六层:任务模板为什么也有自己的黑名单与创建入口
在 project_task.py 里,任务模板同样有:
_get_template_default_context_whitelist()_get_template_field_blacklist()action_create_from_template()
任务级默认允许从上下文传的字段很少,比如:
parent_id
而黑名单同样包含:
partner_id
这说明官方不是只在项目层做模板语义,而是在任务层也维持同样原则:
- 模板是结构和规则
- 实例是具体业务对象
所以模板和实例的客户、负责人、时点等信息,不该机械混在一起。
新手最容易误解的 4 件事
1. 以为模板创建项目就是普通 duplicate
不对。官方专门区分了上下文和入口方法。
2. 以为模板日期应该原样复制
不对。源码明显倾向于保留工期相对关系,而不是复制历史日期。
3. 以为模板客户应该照搬
不对。partner_id 被列入黑名单,说明官方在主动阻止这种误用。
4. 以为模板负责人应该写死在模板里
不对。官方更推荐“角色 → 用户”的落地映射。
实战上最该注意什么
1. 做模板二开时,先区分“结构数据”和“实例数据”
不要什么都 copy。先想清哪些是蓝图,哪些是具体项目事实。
2. 如果你要支持多团队复用模板,优先做角色映射,不要写死用户
这会让模板生命周期长很多。
3. 调试模板生成项目异常时,要看上下文标记
copy_from_template 和 copy_from_project_template 往往直接决定复制分支走向。
一句话记忆法
Odoo 项目模板不是“复制旧项目”,而是“按规则实例化蓝图,并在落地时重算日期、过滤字段、映射角色与重建任务结构”。
DISCUSSION
评论区