先说结论
Odoo Survey 的复杂度,不在于它支持单选、多选、矩阵、日期这些题型,而在于它把“看见什么题、能不能回答、答案存成什么、答卷身份如何被回填”放进了一条连续链路。
从 /home/ubuntu/odoo-temp/addons/survey/models/survey_question.py 可以看到,survey.question 至少同时承担了四层职责:
- 定义题目本身及题型
- 决定题目是否因前题答案而显示
- 对输入值进行结构化校验
- 把某些答案反向写成答卷的身份信息,如邮箱和昵称
所以它真正解决的问题不是:
页面上把题渲染出来。
而是:
如何确保一份答卷从题目可见性、输入合法性到身份字段沉淀,前后一致。
第一层:为什么条件题不是前端小把戏
很多人第一次看到“条件显示”时,会觉得这只是前端 UI 的显隐逻辑。
但 survey.question 里专门有:
triggering_answer_idstriggering_question_idsallowed_triggering_question_idsis_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_email 和 save_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 只拿来做简单投票,当然感觉不到这些设计的价值。
但只要问卷开始承担下面这些任务,它们立刻就重要了:
- 报名前资格判断
- 培训前画像采集
- 线索表单分流
- 直播课堂昵称与邮箱识别
- 多路径、多分支的访谈式问卷
这些场景的共同点是:
答案不仅要被收上来,还要能被后续流程信任。
而要做到这一点,条件依赖、输入验证、身份回填这三层都不能含糊。
最容易误解的三个点
误区一:条件题只是前端隐藏/显示
不是。它有模型级依赖关系和顺序约束。
误区二:所有答案本质上都是文本
不是。不同题型对应不同结构与校验规则。
误区三:邮箱昵称字段只是页面展示用
也不是。它们决定答卷身份如何被系统识别和复用。
实战上怎么用最稳
建议这样设计问卷:
- 先画清楚题目依赖关系,再排题目顺序
- 触发题尽量用明确的单选/多选,不要用语义模糊的文本题
- 需要沉淀身份时,单独做邮箱题和昵称题,不要混进开放式问题
- 长问卷分页面时,先保证依赖链在顺序上自洽,再追求页面美观
- 上线前重点测“触发路径 + 空值 + 非法输入”这三类边界
最后总结
Odoo 问卷最强的地方,不是支持多少题型,而是它把 条件显示、输入验证、答案结构化与身份字段回填 放进了同一个模型语义里。
这让 Survey 不只是一个“收答案”的模块,而是一个能承接分支逻辑和身份沉淀的数据入口。
DISCUSSION
评论区