Django存储订单到会话时Product对象无法JSON序列化问题求解
问题根因分析
该报错的核心原因是Django 2.1及以上版本默认使用JSONSerializer作为会话序列化器,无法直接序列化自定义的Product模型实例。购物车同类操作没有触发报错的原因通常为以下两点:
- 你此前实现Basket类时,存入会话的仅为商品ID、价格、数量等基础类型数据,仅在读取购物车时通过ID查询Product实例做前端展示,没有直接把Product实例存入会话
- 新开发的Orders类逻辑中,直接将Product模型实例放入了待存入会话的订单数据结构中,触发JSON序列化失败
可行解决步骤
方案1:调整订单存储逻辑(推荐,和现有购物车逻辑对齐)
不要在订单条目中直接存储Product实例,仅存入可被JSON序列化的基础字段,同时建议存储商品信息快照,避免后续商品信息修改导致历史订单显示异常:
# 错误写法示例 order_items.append({ "product": product_instance, # 直接存Product实例触发报错 "count": item_count, "subtotal": item_subtotal }) # 修正后写法 order_items.append({ "product_id": product_instance.id, "product_name": product_instance.name, "product_price": str(product_instance.price), "count": item_count, "subtotal": str(item_subtotal) })
后续读取订单数据时,如果需要获取完整Product实例,用存储的product_id查询数据库即可;如果仅做历史订单展示,直接读取已经存储的快照字段即可,无需额外查库。
方案2:自定义模型序列化方法
给Product模型新增序列化方法,将实例转换为可JSON序列化的字典后再存入会话:
class Product(models.Model): # 原有模型字段定义 name = models.CharField(max_length=128) price = models.DecimalField(max_digits=8, decimal_places=2) # 其他字段... def serialize(self): return { "id": self.id, "name": self.name, "price": str(self.price) }
存入订单时调用该方法替换直接存实例即可:"product": product_instance.serialize()
方案3:切换会话序列化器(不推荐生产环境使用)
如果仅为临时测试,可以把Django会话序列化器换回旧版的Pickle序列化器,修改settings.py配置:
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
该方案存在远程代码执行的安全风险,若会话数据被篡改可能导致服务器被攻击,仅可用于本地测试场景,禁止生产环境使用。
注意事项
- Decimal、datetime等特殊类型存入会话前需要提前转换为字符串/数字类型,否则也会触发序列化报错
- 历史订单数据建议优先存快照信息,不要依赖实时数据库查询,避免商品删除、修改后历史订单显示异常
内容的提问来源于stack exchange,提问作者Inexpli
相关产品推荐
相关产品推荐

