Django3.2使用F()自增字段触发DeserializationError错误如何解决?
报错原因
这个错误和你传入的整数1没有任何关系,问题根源在F表达式的运行逻辑和第三方审核模块(moderation)的信号执行顺序冲突:
- F表达式本质是SQL表达式的Python封装,你给
view_count赋值F('view_count') + 1之后,存在当前实例属性上的不是计算后的整数值,而是CombinedExpression表达式对象,这个对象只有在save执行时才会被转换成SQL语句,交由数据库层面完成计算和存储。 - 你原本的逻辑
save之后调用refresh_from_db是正确的,本来可以把数据库中计算完成的整数值拉回实例,覆盖掉之前的表达式对象。但从栈追踪可以明显看到:save执行过程中会触发post_save信号,你使用的moderation模块的post_save_handler逻辑会在refresh_from_db执行前,就尝试读取当前实例的view_count字段做序列化,拿到的还是未计算的表达式对象,自然无法转成整数,就抛出了反序列化错误。
你调试时看到save执行后字段还是表达式对象是正常现象,只要没有其他逻辑在刷新前读取这个字段,就不会出问题,Django官方文档的用法是完全正确的。
解决方案
最优方案:直接用QuerySet的update方法更新(推荐)
完全绕开实例save流程,既保留F表达式的原子性避免竞态条件,也不会触发当前实例的post_save信号,从根源规避冲突:
def __update_fields(self, interaction_type): update_fields = {} if interaction_type == Engagement.VIEW: update_fields['view_count'] = F('view_count') + 1 # 其他要更新的字段同理加入update_fields if update_fields: # 直接在数据库层执行更新,原子操作 self.__class__.objects.filter(pk=self.pk).update(**update_fields) # 刷新实例获取最新值 self.refresh_from_db()
备选方案:跳过moderation模块的本次审核逻辑
如果业务要求必须走实例save流程,可以根据你使用的moderation模块的文档,给save方法加跳过审核的参数,大部分主流moderation库都支持这类配置,比如django-moderation可以加skip_moderation=True参数:
self.save(skip_moderation=True) # 后续再执行refresh_from_db
兜底方案:保存前指定update_fields
如果上述方案都不适用,可以在save时明确指定只更新计数字段,减少不必要的信号逻辑触发:
self.save(update_fields=['view_count']) self.refresh_from_db()
内容的提问来源于stack exchange,提问作者Homunculus Reticulli
相关产品推荐
相关产品推荐

