网站对比

Odoo 商品对比为什么不是“并排摆出来”这么简单:属性分组、变体边界与价格展示主链路讲透

很多人把 Odoo 的商品对比理解成一个前端表格,但 website_sale_comparison 实际把最多对比数量、属性分类、变体值展示、图片与价格口径串成了一套帮助决策的对比机制。

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

先说结论

Odoo 的商品对比功能,不是把几个商品卡片横着摆一排这么简单。

website_sale_comparison 真正在解决的,是“如何把不同商品的可比信息组织成一个可读、可决策的页面”。

它至少处理了这些问题:

  • 对比页怎么取商品;
  • 最多允许同时比较多少个;
  • 变体商品到底展示哪一层属性值;
  • 属性应该如何按类别分组,而不是乱成一张大表;
  • 价格、划线价、图片 URL 用什么口径回给前端。

所以这个模块更像:

一套把商品复杂配置翻译成“用户可比较信息结构”的展示引擎。


一、为什么对比页本质上是一个“受约束的选择集合”

/shop/compare 会从 URL 参数里读取 products,再用 product.product 去搜索有效记录。

这里至少传达了两个信号:

  1. 对比页对的是 具体变体级商品,而不只是模板;
  2. 最终能否展示,还要重新经过搜索与读取权限校验。

换句话说,对比页不是前端自己缓存几条卡片就算完成,而是后端重新确认:

  • 这些商品 ID 是合法的吗;
  • 当前访客能不能读到;
  • 页面应该基于哪一批真实商品对象渲染。

这能避免前端状态漂移太远,也让分享型 compare URL 更可靠。


二、为什么系统要强行限制最多 4 个商品

前端交互里明确写了:

You can compare up to 4 products at a time.

很多人第一反应会觉得这是 UI 保守,但从产品角度看,这其实很合理。

因为商品对比不是越多越好。

当对比项一多,页面会迅速出现三个问题:

  • 横向信息密度爆炸;
  • 属性行数过多导致用户根本看不完;
  • 购买决策反而被拖慢。

Odoo 把上限收在 4,本质上是在承认一个事实:

对比页的目标不是做数据库导出,而是帮助用户尽快做出购买选择。

这和“功能越多越强”是两种完全不同的产品思路。


三、为什么属性必须先按 category 分组

_prepare_categories_for_display()product.template.attribute.lineproduct.product 两层都做了相似动作:

  • 先拿到属性;
  • product.attribute.category 排序和分组;
  • 没有 category 的属性也不会丢,而是放进一个空类别槽位;
  • 最终返回有序的 OrderedDict

这背后的好处非常直接:

如果没有 category,对比页会变成一串无序属性:颜色、尺寸、材质、续航、接口、重量全部混在一起。

而有了 category 之后,页面才能呈现更接近人类决策方式的结构,比如:

  • 基础特性
  • 设计与尺寸
  • 选项与配置
  • 续航与性能

这一步看似是显示细节,实际上决定了用户能不能“扫读”对比结果。

所以 Odoo 不是简单地把属性表扔到模板里,而是在源码层先做信息架构整理。


四、为什么变体值展示不是只拿当前值那么简单

product.product._prepare_categories_for_display() 有一段非常关键:

对每个属性,系统会优先拿当前 product 的 product_template_attribute_value_ids; 如果某些属性属于 no_variant 情况,没有具体变体值,它就退回到 attribute line 上的全部可能值。

这个设计很重要。

因为现实里并不是每个可展示属性都会映射成一个真正切换 SKU 的变体。

如果系统只展示“当前变体值”,你可能会出现:

  • 某些属性在比较表里莫名空白;
  • 用户误以为商品没有该属性;
  • 模板层配置和变体层表现严重脱节。

Odoo 的处理更稳妥:

对比页要展示的是“用户认知上属于这个商品的信息”,而不只是严格的 SKU 差异字段。

这让对比更接近商品说明,而不是数据库结构裸露。


五、为什么价格返回的是组合信息而不是裸字段

/shop/compare/get_product_data 不直接读简单价格字段,而是调用 _get_combination_info_variant()

然后再从组合信息里取:

  • display_name
  • website_url
  • image_url
  • price
  • prevent_zero_price_sale
  • currency
  • list_pricecompare_list_price 对应的划线价

这说明对比页价格不是静态 catalog 数据,而是:

  • 已经考虑变体上下文;
  • 已经考虑是否显示划线价;
  • 已经考虑零价商品的销售限制;
  • 已经返回可直接给前端渲染的口径。

对前台体验来说,这很关键。

因为用户在 compare 页看到的价格,必须尽量和商品页、变体选择后的价格保持一致,否则信任立刻下降。


六、为什么图片 URL 也要单独封装

_get_image_1024_url() 专门通过 website.image_url() 返回本地图片地址。

这看起来像小事,但它体现出 Odoo 的一致性思路:

  • 对比页不应该自己猜图片路径;
  • 图片输出要走 website 层统一口径;
  • 前端拿到的是可直接消费的 URL,而不是还要再拼装的字段片段。

这能减少前端模板和不同页面之间的实现偏差。


七、为什么商品对比其实在倒逼商品数据建模

很多团队上线 compare 功能后才会发现:

  • 属性没有分类;
  • 属性命名不统一;
  • 有些信息写在销售描述里,没有进属性体系;
  • 变体和 no_variant 属性边界混乱。

一旦这样,对比页就会立刻暴露数据治理问题。

因为 compare 页是最不讲情面的:

它会把你的商品结构原封不动地并排摆出来。

所以 website_sale_comparison 的价值不只在前端功能,还在于它反过来督促你把商品属性建模做干净。


八、实施时最容易踩的坑

1. 只开功能,不整理 attribute category

结果就是表格很长,但用户完全抓不到重点。

2. 误把模板描述当可比较数据

说明文案可以很长,但对比页真正需要的是可结构化字段。

3. 忽视 no_variant 属性

如果你的数据设计里这类属性很多,却没理解回退逻辑,就容易误判页面为何出现“多值展示”。

4. 让 compare 页承载过多商品

即便你能技术上放开限制,用户认知负担也未必能承受。


最后总结

website_sale_comparison 真正做的不是“商品并排显示”,而是:

  • 控制比较集合的大小;
  • 以变体为核心组织对比对象;
  • 把属性按 category 重构成可读结构;
  • 在变体值和模板值之间找到合理展示边界;
  • 保证价格、图片和展示名称与前台口径一致。

所以它本质上不是一个表格插件,而是:

把 Odoo 商品配置体系翻译成购买决策页面的一层解释器。

如果你的商品数据建模清楚,它会非常有帮助; 如果你的属性体系很乱,它也会毫不客气地把问题摊在用户面前。

DISCUSSION

评论区

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