其他深度

Odoo 问卷为什么不只是“按顺序出题”:条件显示、答案落库与身份字段回填链路讲透

很多人以为 Odoo Survey 的难点只是题型多,但从 survey_question.py 里的 triggering_answer_ids、allowed_triggering_question_ids、save_as_email 与 validate_question 逻辑看,它真正复杂的地方在于:题目显示顺序、答案是否合法、以及答案如何反过来塑造答卷身份。看懂这条链,问卷实施才不会表面可用、底层失真。

其他
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo Survey 的复杂度,不在于它支持单选、多选、矩阵、日期这些题型,而在于它把“看见什么题、能不能回答、答案存成什么、答卷身份如何被回填”放进了一条连续链路。

/home/ubuntu/odoo-temp/addons/survey/models/survey_question.py 可以看到,survey.question 至少同时承担了四层职责:

  • 定义题目本身及题型
  • 决定题目是否因前题答案而显示
  • 对输入值进行结构化校验
  • 把某些答案反向写成答卷的身份信息,如邮箱和昵称

所以它真正解决的问题不是:

页面上把题渲染出来。

而是:

如何确保一份答卷从题目可见性、输入合法性到身份字段沉淀,前后一致。

第一层:为什么条件题不是前端小把戏

很多人第一次看到“条件显示”时,会觉得这只是前端 UI 的显隐逻辑。

survey.question 里专门有:

  • triggering_answer_ids
  • triggering_question_ids
  • allowed_triggering_question_ids
  • is_placed_before_trigger

这说明官方把条件题看成了模型级约束,而不是页面糖衣。

尤其 allowed_triggering_question_ids 的计算,会根据题目在数据库中的 sequence 和 id,严格筛出当前题之前、且可作为触发源的问题。

换句话说,Odoo 不只是问“你想依赖哪道题”,而是追问:

  • 这道题是不是本问卷里的题
  • 它是不是选择题、并且确实有候选答案
  • 它在顺序上是不是出现在当前题之前

这就避免了一个很常见的坑:

把后面的问题拿来控制前面的问题。

一旦允许这种倒挂,问卷逻辑就会失去时间顺序,前端即使暂时能渲染,后台数据也会变得不可解释。

第二层:为什么“题目顺序”会影响业务正确性

_compute_allowed_triggering_question_ids() 有一段很值得注意的实现:它会主动读取数据库里已有问题的 sequence,而不是完全依赖页面临时状态。

这意味着官方很清楚:

  • 问卷编辑器里拖拽排序经常发生
  • 条件题依赖关系一旦错位,用户很难立刻感知
  • 如果只相信前端临时顺序,保存结果可能和真实数据库顺序不一致

所以它宁愿在模型层多做一次校验,也要把“触发题必须在前”这条规则守住。

这件事听起来很细,但对问卷准确性影响极大。

因为一张问卷真正难维护的,不是题目数量,而是逻辑依赖越来越多以后,顺序变化会不会把整张问卷暗中改坏

第三层:为什么输入验证不是统一一把梭

validate_question() 会根据题型,把答案分流到不同校验逻辑:

  • 文本框看字符约束
  • 数值题看数值合法性
  • 日期/日期时间题看格式与范围
  • 选择题看候选项是否匹配
  • 矩阵题看行列结构是否完整

而且 mandatory 校验也不是简单判断“answer 是否为空”,因为:

  • 选择题可能允许 comment 作为答案
  • 条件题可能根本不该出现
  • 不同题型的空值定义并不一样

这说明 Odoo 的思路非常务实:

问卷答案不是一段文本,而是一种有题型语义的数据。

只有把题型语义带进验证,后面的评分、导出、CRM 衔接、证书判断才站得住。

第四层:为什么 save_as_emailsave_as_nickname 这么重要

很多实施会忽略 save_as_email / save_as_nickname,把它们当成顺手的小选项。

其实这两个字段非常关键,因为它们说明 Survey 不只是收集答案,还会从答案里提炼参与者身份

源码里:

  • save_as_email 只在 char_box + validation_email 条件下成立
  • save_as_nickname 也只在字符题里可用

这个限制很合理。因为系统不是要把任何答案都乱写成身份字段,而是要求:

  • 题型必须适合承载身份值
  • 邮箱还必须满足 email 校验

这样问卷入口才能支撑更多场景:

  • 匿名问卷与实名问卷切换
  • Live Session 昵称展示
  • 邮件邀请后的答卷归档
  • 证书或结果通知的收件识别

也就是说,问卷不是在单独跑,它会把答案接回用户身份层。

第五层:为什么 page 和 question 共用模型仍然成立

虽然这轮我们不讲随机抽题,但 survey.question 同时承载 page 与 question 的设计,仍然对条件显示有直接影响。

因为条件题不是悬浮在问卷之外的,它要嵌在具体的页面和顺序里。

当 page 本身也是同一模型中的记录时,系统在计算:

  • 当前题属于哪一页
  • 当前题前面有哪些题
  • 条件题是否摆在触发题之后

就能沿着同一条序列处理。

这比“页面一个模型、题目一个模型、条件关系再单独做一层映射”更容易保持一致性。

代价是模型看起来更复杂,但收益是:顺序、页结构与条件显示能共用同一套语义。

第六层:这套机制最适合解决什么问题

如果你把 Odoo Survey 只拿来做简单投票,当然感觉不到这些设计的价值。

但只要问卷开始承担下面这些任务,它们立刻就重要了:

  • 报名前资格判断
  • 培训前画像采集
  • 线索表单分流
  • 直播课堂昵称与邮箱识别
  • 多路径、多分支的访谈式问卷

这些场景的共同点是:

答案不仅要被收上来,还要能被后续流程信任。

而要做到这一点,条件依赖、输入验证、身份回填这三层都不能含糊。

最容易误解的三个点

误区一:条件题只是前端隐藏/显示

不是。它有模型级依赖关系和顺序约束。

误区二:所有答案本质上都是文本

不是。不同题型对应不同结构与校验规则。

误区三:邮箱昵称字段只是页面展示用

也不是。它们决定答卷身份如何被系统识别和复用。

实战上怎么用最稳

建议这样设计问卷:

  1. 先画清楚题目依赖关系,再排题目顺序
  2. 触发题尽量用明确的单选/多选,不要用语义模糊的文本题
  3. 需要沉淀身份时,单独做邮箱题和昵称题,不要混进开放式问题
  4. 长问卷分页面时,先保证依赖链在顺序上自洽,再追求页面美观
  5. 上线前重点测“触发路径 + 空值 + 非法输入”这三类边界

最后总结

Odoo 问卷最强的地方,不是支持多少题型,而是它把 条件显示、输入验证、答案结构化与身份字段回填 放进了同一个模型语义里。

这让 Survey 不只是一个“收答案”的模块,而是一个能承接分支逻辑和身份沉淀的数据入口。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。