I'm overwriting the save method of a ModelForm
and I don't know why it would cause recursion:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountForm, self).save(*args,**kwargs)
Causes this:
maximum recursion depth exceeded while calling a Python object
Stacktrace shows this line repetitively calling itself:
return super(AccountForm, self).save(*args,**kwargs)
Now, the parsley decorator is like this:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
As @DanielRoseman suggested that the Parsley decorator extending the AccountForm
causes the super(AccountForm,self)
to keep calling itself, what's the solution?
Also I cannot get my head around this why this would cause recursion.
What you could do is just call the parent's method directly:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return forms.ModelForm.save(self, *args,**kwargs)
This should neatly avoid the issue introduced by your class decorator. Another option would be to manually call the decorator on a differently named base class, rather than using @
syntax:
class AccountFormBase(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountFormBase, self).save(*args,**kwargs)
AccountForm = parsleyfy(AccountFormBase)
However, you might also want to consider using a pre-save signal instead, depending on what you're trying to do - it's how one normally adds functionality that should happen before the rest of the model save process in Django.
As for why this is occurring, consider what happens when the code is evaluated.
First, a class is declared. We'll refer to this original class definition as Foo
to distinguish it from the later class definition that the decorator will create. This class has a save
method which makes a super(AccountForm, self).save(...)
call.
This class is then passed to the decorator, which defines a new class which we'll call Bar
, and inherits from Foo
. Thus, Bar.save
is equivalent to Foo.save
- it also calls super(AccountForm, self).save(...)
. This second class is then returned from the decorator.
The returned class (Bar
) is assigned to the name AccountForm
.
So when you create an AccountForm
object, you're creating an object of type Bar
. When you call .save(...)
on it, it goes and looks up Bar.save
, which is actually Foo.save
because it inherited from Foo
and was never overridden.
As we noted before, Foo.save
calls super(AccountForm, self).save(...)
. The problem is that because of the class decorator, AccountForm
isn't Foo
, it's Bar
- and Bar
's parent is Foo
.
So when Foo.save
looks up AccountForm
's parent, it gets... Foo
. This means that when it tries to call .save(...)
on that parent, it actually just winds up calling itself, hence the endless recursion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With