Django Model中super()方法的异常递归调用问题
解决Django模型save方法中super()递归调用的问题
听起来你遇到的这个递归问题,大概率和Python 2.7中super()的调用方式,以及DRF处理POST请求时的模型保存逻辑有关。我来帮你拆解可能的原因和解决方案:
一、最可能的根源:Python 2.7中super()的调用错误
Python 2.7里的super()和Python 3不一样,必须显式传递当前类和实例对象,如果写法不对,会导致方法解析顺序(MRO)出错,进而触发递归调用。
错误写法(会导致递归):
def save(self, *args, **kwargs): # 你的自定义逻辑 super().save(*args, **kwargs) # Python 2.7不支持无参数super()
这种写法在Python 2.7中不会正确指向父类的save方法,反而可能又调用回当前类的save,形成递归。
正确写法:
class MyModel(models.Model): # 你的字段定义 def save(self, *args, **kwargs): # 先执行你的自定义逻辑 # 比如字段修改、校验等 self.some_field = "modified_value" # 显式传递类和实例给super super(MyModel, self).save(*args, **kwargs)
二、检查自定义逻辑是否触发重复保存
如果你的save方法里修改了模型字段,又没有指定update_fields参数,可能会在父类save执行时再次触发模型的保存流程(比如通过信号、DRF序列化器的额外逻辑),尤其在单元测试的POST请求场景下,DRF会完整走序列化-保存的流程,更容易触发递归。
优化方案:指定update_fields减少不必要的保存
def save(self, *args, **kwargs): # 修改字段 self.some_field = "modified_value" # 只更新修改过的字段,避免触发完整的保存流程 if 'update_fields' not in kwargs: kwargs['update_fields'] = [] if 'some_field' not in kwargs['update_fields']: kwargs['update_fields'].append('some_field') super(MyModel, self).save(*args, **kwargs)
三、调试定位递归触发点
如果上面的方法还没解决问题,建议加调试日志或者断点,确认递归的调用来源:
- 添加日志打印:
import inspect def save(self, *args, **kwargs): print(f"[DEBUG] Entering MyModel.save, pk={self.pk}, caller={inspect.stack()[1][3]}") # 你的自定义逻辑 super(MyModel, self).save(*args, **kwargs)
这样可以看到每次调用save的上层调用者,判断是DRF序列化器、信号还是其他逻辑触发的。
- 使用pdb断点调试:
import pdb def save(self, *args, **kwargs): pdb.set_trace() # 运行到这里会进入调试模式 # 你的自定义逻辑 super(MyModel, self).save(*args, **kwargs)
在调试模式下,用w命令查看调用栈,就能清楚看到递归的触发路径。
四、DRF场景的额外注意点
单元测试中用self.client.post(...)时,DRF的序列化器会调用模型的save方法,如果你在序列化器里也自定义了create/update方法,可能会和模型的save逻辑形成交互,导致重复调用。建议检查序列化器的代码,确保没有额外的保存逻辑和模型save冲突。
内容的提问来源于stack exchange,提问作者Roman Storozhenko
相关产品推荐
相关产品推荐

