我正在覆盖 ModelForm
的保存方法,我不知道为什么会导致递归:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountForm, self).save(*args,**kwargs)
原因:
maximum recursion depth exceeded while calling a Python object
Stacktrace 显示此行重复调用自身:
return super(AccountForm, self).save(*args,**kwargs)
现在,欧芹装饰器是这样的:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
正如@DanielRoseman 所说,扩展 AccountForm
的 Parsley 装饰器会导致 super(AccountForm,self)
继续调用自身,解决方案是什么?
我也无法理解为什么这会导致递归。
最佳答案
你可以做的就是直接调用父类的方法:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return forms.ModelForm.save(self, *args,**kwargs)
这应该巧妙地避免类装饰器引入的问题。另一种选择是在不同名称的基类上手动调用装饰器,而不是使用 @
语法:
class AccountFormBase(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountFormBase, self).save(*args,**kwargs)
AccountForm = parsleyfy(AccountFormBase)
但是,您可能还想考虑使用 pre-save signal相反,这取决于您尝试做什么 - 这是通常添加功能的方式,应该在 Django 中的模型保存过程的其余部分之前发生。
至于为什么会发生这种情况,请考虑评估代码时会发生什么。
首先,声明一个类。我们将这个原始类定义称为 Foo
以将其与装饰器将创建的后续类定义区分开来。此类有一个 save
方法,它会调用 super(AccountForm, self).save(...)
。
这个类然后被传递给装饰器,装饰器定义了一个我们称之为Bar
的新类,并继承自Foo
。因此,Bar.save
等同于 Foo.save
- 它也调用 super(AccountForm, self).save(...)
。然后从装饰器返回第二个类。
返回的类 (Bar
) 被分配给名称 AccountForm
。
因此,当您创建一个 AccountForm
对象时,您正在创建一个类型为 Bar
的对象。当你调用 .save(...)
时,它会去查找 Bar.save
,它实际上是 Foo.save
因为它继承自 Foo
并且从未被覆盖。
如前所述,Foo.save
调用 super(AccountForm, self).save(...)
。 问题是因为类装饰器,AccountForm
不是Foo
,而是Bar
- 和Bar
的父级是 Foo
。
所以当 Foo.save
查找 AccountForm
的父级时,它得到... Foo
。这意味着当它试图在该父级上调用 .save(...)
时,它实际上只是调用自身,因此无休止的递归。
关于Python类装饰器扩展类导致递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14739809/