Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract Inheritance in Django Model, causing MAX recursion depth error

I'm trying to implement abstract inheritance in Django with the following code, but it produces a MAX recursion depth error. I'm trying to override a model's save method.

class BaseModel(models.Model):
    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        #i'm doing something here

        #i think the problem is in the return statement specifically because of the
        #self.__class__ expression.
        return super(self.__class__, self).save(*args, **kwargs)

class MyModel(BaseModel):
    p = models.CharField(max_length=30)

produces this error (end of the trace, it's lengthy):

  File "/home/jultra/ap3w/jultra_01/mysite/testsite/models.py", line 10, in save
    return super(self.__class__, self).save(*args, **kwargs)
  File "/home/jultra/ap3w/jultra_01/mysite/testsite/models.py", line 10, in save
    return super(self.__class__, self).save(*args, **kwargs)
  File "/home/jultra/ap3w/jultra_01/mysite/testsite/models.py", line 10, in save
    return super(self.__class__, self).save(*args, **kwargs)
  File "/home/jultra/ap3w/jultra_01/mysite/testsite/models.py", line 10, in save
    return super(self.__class__, self).save(*args, **kwargs)
RuntimeError: maximum recursion depth exceeded
like image 228
ultrajohn Avatar asked Jun 08 '12 11:06

ultrajohn


1 Answers

Do not call super on self.__class__! Call it on the actual class:

return super(BaseModel, self).save(*args, **kwargs)

This is because self.__class__ always refers to the actual concrete class of the instance. So if you inherit MyModel from BaseModel, when you get to the save method in BaseModel self.__class__ is still MyModel. So it finds the super of MyModel, which is BaseModel, so calls the save in BaseModel, which once again finds the super of MyModel...

like image 82
Daniel Roseman Avatar answered Nov 04 '22 17:11

Daniel Roseman