Asif Rahman
Asif Rahman

Reputation: 247

Overriding __getattribute__ for the Model class in Django

In Django, I need to create a model in which an instance of that model can inherit values from another instance of that model in what amounts to a superclass-subclass type relationship. I created a field in this model called parent, which is an optional self-referencing foreign key. I then want to override the __getattribute__ method as follows:

def __getattribute__(self, name):
    if models.Model.__getattribute__(self, 'parent') is None:
        return models.Model.__getattribute__(self, name)
    elif models.Model.__getattribute__(self, name) is not None:
        return models.Model.__getattribute__(self, name)
    else:
        return parent.__getattribute__(name)

This code causes an infinite recursion because the __get__ method of the Model class calls the built-in method getattr passing in the instance as the first parameter.

Is there another way to accomplish what I'm trying to do?

Upvotes: 2

Views: 3404

Answers (3)

Anatoly Scherbakov
Anatoly Scherbakov

Reputation: 1752

I suppose that overriding __getattribute__ or __getattr__ may lead to performance cost. Probably there is a better way to solve this problem:

  1. On model instance initialization, if an inheritable field is empty and corresponding parent's field is not, do setattr(self, field_name, getattr(self.parent, field_name)).
  2. Keep track of model instance field changes.
  3. Before saving the instance, set the fields that were previously overridden but not changed to None.

I'm developing a Django app for that: https://github.com/Altaisoft/django-inheritance

Upvotes: 1

S.Lott
S.Lott

Reputation: 391818

This is fraught with difficulty when done this way.

Please reconsider overriding __getattribute__ and use a plain old properties for this.

I suspect that a simple "getter" with a property names will do eveything you want without bumping into any magic.

Yes, you may have several similar fields, but I think that simple, obvious properties fit better with the Django ORM.

Upvotes: 3

Denis Otkidach
Denis Otkidach

Reputation: 33180

Do you need that parent's attributes shadow own ones? If not, you'd better overwrite __getattr__() instead of __getattribute__() which is not called when instance itself has property with this name:

def __getattr__(self, name):
    return getattr(self.parent, name)

Upvotes: 2

Related Questions