Search code examples
djangodjango-modelsdjango-inheritance

Partial model inheritance in Django


I have a model that I'm using as a reference point to create another model:

class ImYourFather(models.Model):
    force = fields.HTMLField(null=True, blank=True)
    supermarket_planets = models.HTMLField(null=True, blank=True)
    destroying_planets = models.HTMLField()

class Luke(ImYourFather):
    # Inheriting all the fields from father
    the_cool_kid = models.HTMLField() # extra field added

I DO NOT want to inherit the destroying_planets field, Is this possible?
I'm asking specifically because destroying_planets is supposed to be mandatory in the father model but I'd like to have it optional in the child model.
Is this achievable in another way?


Solution

  • You can't partially inherit but you can manually create the models with whatever fields you need. This is not exactly the same as multi-table inheritance but that is the only way to partially inherit fields:

    class Base(models.Model):
        force = fields.HTMLField(null=True, blank=True)
        supermarket_planets = models.HTMLField(null=True, blank=True)
    
        class Meta(object):
            abstract = True
    
    class ImYourFather(Base):
        destroying_planets = models.HTMLField()
    
    class Luke(Base):
        # optional in case you need this
        father = models.OneToOneField(ImYourFather, related_name='lukes')
        the_cool_kid = models.HTMLField() # extra field added
    

    edit

    Another approach is to simply copy the fields from the father. This is all untested so Django might bark at you for some of it). The advantage is that no monkey-patching but should work:

    exclude = ['id', 'destroying_planets']
    try: # Django 1.7
        fields = {i.attname: i.clone() for i in ImYourFather._meta.fields if not i.attname in exclude}
    except AttributeError: # Django < 1.7
        fields = {i.attname: deepcopy(i) for i in ImYourFather._meta.fields if not i.attname in exclude}
    Base = type('Base', (models.Model,), fields)
    
    class Luke(Base):
        # optional in case you need this
        father = models.OneToOneField(ImYourFather, related_name='lukes')
        the_cool_kid = models.HTMLField() # extra field added