先说结论
Odoo 的活动模板不是一个“复制字段”的小工具,而是活动运营的默认配置中心。
从 /home/ubuntu/odoo-temp/addons/event/models/event_event.py 看,event.type 往 event.event 继承时,官方重点处理的不是“拷贝得快不快”,而是三件更难的事:
- 默认邮件计划怎么灌进活动
- 默认报名问题怎么灌进活动
- 当活动已经有历史报名后,模板变更如何避免把旧数据冲掉
所以它真正解决的问题不是:
如何一键新建活动。
而是:
如何让活动吃到模板默认值,同时不破坏已经发生的报名、邮件发送和票种历史。
第一层:为什么模板同步不是简单 copy
event.event 上有几组典型字段:
event_mail_idsquestion_idsevent_ticket_idsticket_instructions
这些都不是随便填的普通字段,而是带 compute、store、readonly=False 的“可继承默认值”。
这很关键。
因为官方显然不想把活动模板做成“一次性复制”。如果只是复制,那么后续切换模板、补默认项、保留已使用项这些问题都会变得很难处理。
现在这套设计更像:
- 活动可以从模板吸收默认配置
- 但活动对象仍保留自己的独立记录
- 同步时要区分“可删除的默认项”和“已经参与业务的历史项”
也就是说,模板继承在 Odoo 里不是纯静态动作,而是带边界条件的同步行为。
第二层:为什么邮件计划同步要先判断“有没有发过、有没有挂过报名”
_compute_event_mail_ids() 的注释写得非常直白:
- 没发过、也没有关联报名记录的 mail line,可以移除
- 已经发过,或者已经绑定过报名记录的 line,要保留
- 模板里有但活动里还没有的 line,再补进来
这背后有一个很现实的业务判断:
邮件计划不是纯配置,它会演变成历史事实。
一旦某条活动邮件:
- 已经发给过参会者
- 或已经和某些注册记录建立了关系
它就不再只是模板衍生物,而是运营历史的一部分。
如果这时你切换 event type,系统还粗暴地把旧 line 全删掉,后果会很糟:
- 邮件发送记录不好追
- 自动化链路断裂
- 前后台看到的活动沟通历史不一致
所以 Odoo 的策略很稳:默认值可以同步,已发生的动作不能随便抹。
第三层:为什么报名问题同步优先保护“已经有人答过”的题
_compute_question_ids() 的保护思路和邮件计划类似,但更敏感。
源码里会明确保留:
- 已经出现在当前活动里
- 且已有参会者答案的那些问题
换句话说,如果某个问题已经被报名人回答过,那么它就不再只是“模板上的题”,而是报名数据结构的一部分。
这点非常重要,因为活动报名问题不是纯展示字段,它往往被用来收集:
- 饮食偏好
- 发票信息
- 公司与职位
- 出席意向
- 现场特殊需求
一旦用户答过,后台再把题删除,就会出现很尴尬的局面:
- 你还能看到旧答案,但题目没了
- 导出结果时字段语义不完整
- 报名表前后版本不一致
所以官方在这里采用的是“保留已被回答的问题,补齐模板新增问题,清掉未使用的旧问题”。
这其实是在保护表单演化的连续性。
第四层:票种同步为什么同样受“历史报名”约束
_compute_event_ticket_ids() 也不是一股脑重建,而是:
- 没有关联报名的 ticket 可以移除
- 已经有 registration 的 ticket 要保留
- 模板里新增的票种可补到活动里
这说明在 Odoo 看来,票种并不是一个简单标签,而是报名记录的结构支点。
因为报名人一旦挂上了某个 ticket:
- 价格
- 配额
- 报表口径
- 人群区分
都会围绕这个 ticket 展开。
如果模板切换时把旧票种删光,历史订单、席位统计和报名标签都会跟着失真。
所以你可以把这套逻辑理解成:
模板负责给未来配置默认值,历史报名负责给过去建立不可轻易改写的事实。
第五层:为什么 ticket_instructions 只在内容为空时继承
还有一个很容易被忽略的细节:_compute_ticket_instructions() 并不会每次都用模板强刷活动说明。
它只在活动自身说明为空、而模板里有内容时,才把模板值带过来。
这体现了 Odoo 对“模板默认值”和“活动个性化编辑”的边界判断:
- 模板用来帮你起步
- 活动一旦做了明确改写,就尊重活动本身
这比“模板永远覆盖活动”聪明得多。
因为实际运营里,很多活动共享同一模板,但票面说明常常需要微调,比如:
- 入场路线不同
- 签到时间不同
- 场馆注意事项不同
如果每次模板刷新都把这些个性化说明冲掉,模板就会从效率工具变成干扰源。
第六层:这套机制对运营最大的价值是什么
很多团队第一次看 Event Type,会把它理解成“少填几次表单”。
但从源码看,它真正值钱的地方是:
- 让活动创建时自动带出统一默认配置
- 让后续模板调整还能尽量补齐未使用的默认项
- 同时保护已发出的邮件、已回答的问题、已使用的票种
这意味着它不是“复制器”,而是一个带历史保护能力的模板同步器。
这种设计很适合活动运营,因为活动不像 CRM 主数据那样可以无限修订。活动一旦开放报名,很多字段就已经进入事实世界,不能再像草稿一样随便推翻。
最容易误解的三个点
误区一:切换活动模板会把活动彻底重建
不会。Odoo 会尽量只同步可安全变动的默认项。
误区二:邮件计划永远是模板附属物
不是。邮件一旦发出或绑定报名记录,就变成活动历史的一部分。
误区三:报名问题只是表单文案
也不是。它一旦被回答,就已经和历史报名数据强绑定。
实战上怎么用最稳
如果你在做活动实施,我更建议这样用:
- 把 Event Type 当成“默认配置蓝图”,不是万能后悔药
- 活动开放报名前,尽量把问题、票种、邮件计划定稳
- 报名开始后,优先新增而不是粗暴替换已有问题和票种
- 活动特有的票面说明在 event 上单独微调,不要总想着回写模板
- 需要大改流程时,新建模板往往比硬改旧模板更稳
最后总结
Odoo 活动模板最厉害的地方,不是帮你省几次录入,而是它知道:
- 什么属于可复用默认值
- 什么一旦进入运营历史就该被保护
所以 Event Type 真正扮演的是 “模板继承 + 历史数据护栏” 的角色。理解这一点,你就不会把活动模板用成一个反复覆盖现场数据的危险开关。
DISCUSSION
评论区