In Django - Model Inheritance - Does It Allow You to Override a Parent Model's Attribute

In Django - Model Inheritance - Does it allow you to override a parent model's attribute?

Updated answer: as people noted in comments, the original answer wasn't properly answering the question. Indeed, only the LongNamedRestaurant model was created in database, Place was not.

A solution is to create an abstract model representing a "Place", eg. AbstractPlace, and inherit from it:

class AbstractPlace(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()

class Meta:
abstract = True

class Place(AbstractPlace):
pass

class LongNamedRestaurant(AbstractPlace):
name = models.CharField(max_length=255)
food_type = models.CharField(max_length=25)

Please also read @Mark answer, he gives a great explanation why you can't change attributes inherited from a non-abstract class.

(Note this is only possible since Django 1.10: before Django 1.10, modifying an attribute inherited from an abstract class wasn't possible.)

Original answer


Since Django 1.10 it's
possible!
You just have to do what you asked for:

class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()

class Meta:
abstract = True

class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)

Overwrite parent model attribute from child model

This is not possible without an abstract parent model, unfortunately.

Field name “hiding” is not permitted


In normal Python class inheritance, it is permissible for a child class to override any attribute from the parent class. In Django, this isn’t usually permitted for model fields. If a non-abstract model base class has a field called author, you can’t create another model field or define an attribute called author in any class that inherits from that base class.

This restriction doesn’t apply to model fields inherited from an abstract model. Such fields may be overridden with another field or value, or be removed by setting field_name = None.

A recommendation instead would be to simply create a property or rename the child model's field. Another thing you could do is remove the parent model's "company" field and move it to all of the children models instead.

class ModelChild(ModelParent)

child_company = models.CharField(max_length=10, blank=True)
...........

Django model inheritance - How to set value for parent attribute

When I first made the question I was confused because I couldn't see the value for the attribute being set in the subclass in the /admin interface, but the code actually works.

The parent class is an abstract class that contains the definition of the attribute.

The child class inherits this attribute correctly and sets its value.

When navigating the admin panel for this model, the value of the attribute will not show, as it is established by default and will never change, but this attribute is still correctly set and accessible from everywhere else.

See Django docs on abstract model classes

Django model inheritance, overriding fields

Don't think this has been allowed in django, not even 1.0.

From Field name “hiding” is not permitted - django 1.0

In normal Python class inheritance, it is permissible for a child
class to override any attribute from the parent class. In Django, this
is not permitted for attributes that are Field instances (at least,
not at the moment). If a base class has a field called author, you
cannot create another model field called author in any class that
inherits from that base class.

This still holds for the latest version of django.

Django model inheritance overriding a variable used in field attribute

Unfortunately, that's not how Python classes work. The code in the class body (including the field constructors) is evaluated when the class is defined. So at the point when the subclass is defined, the field constructors have already been called and those values are locked in.

In addition, the Django ORM doesn't support overriding model fields. The ImageKit fields aren't regular model fields, but since Django doesn't support this feature anyway, it's not something IK supports. (I'm a maintainer.)

So you're either going to have to live with some duplication or delve into the world of metaclasses. Alternatively, you can create a spec class that varies based on the model.

Help a Python newbie with a Django model inheritance problem

No, Django doesn't allow that.

See the docs: http://docs.djangoproject.com/en/1.1/topics/db/models/#field-name-hiding-is-not-permitted

Also answered in other questions like: In Django - Model Inheritance - Does it allow you to override a parent model's attribute?



Related Topics



Leave a reply



Submit