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)
Answer from qmarlats on Stack Overflow
🌐
Django
docs.djangoproject.com › en › 6.0 › topics › db › models
Models | Django documentation | Django
For many uses, this type of model inheritance will be exactly what you want. It provides a way to factor out common information at the Python level, while still only creating one database table per child model at the database level. When an abstract base class is created, Django makes any Meta inner class you declared in the base class available as an attribute.
🌐
Medium
foysalff.medium.com › understanding-django-model-inheritance-b0c38588ebb4
Understanding Django-Advanced Model Inheritance. | by The CodeCrafter | Medium
August 17, 2024 - We’ll keep things simple, so you can quickly grasp the concepts and start using them in your Django projects. ... Model inheritance in Django lets you create a base model that other models can inherit from. This is useful when you have several ...
🌐
DEV Community
dev.to › highcenburg › django-model-inheritance-4f3p
Django Model Inheritance - DEV Community
May 8, 2023 - Multi-table inheritance can be created by defining a model that inherits from another model. from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) email ...
🌐
B-List
b-list.org › weblog › 2023 › dec › 12 › django-model-inheritance
Django's three types of model inheritance
December 12, 2023 - The best case for inheritance in Django models is abstract models, which can’t be instantiated or saved on their own, but rather define a useful set of base fields or methods (or both) to be inherited into and reused by other models.
🌐
LinkedIn
linkedin.com › pulse › mastering-djangos-model-inheritance-ali-ranjbar-mes5f
Mastering Django's Model Inheritance
February 12, 2024 - Introduction: Model inheritance is a powerful feature in Django that allows developers to create relationships between models, enabling code reusability and maintainability. In this article, we'll explore the three main approaches to model ...
🌐
Medium
medium.com › @altafkhan_24475 › what-is-inheritance-in-django-59ee3a47cc54
What is model inheritance in django | by Altaf Khan | Medium
March 9, 2024 - What is model inheritance in django Introduction In Django, inheritance in models allows you to define relationships between models where one model can inherit fields and methods from another. Django …
🌐
MakeUseOf
makeuseof.com › home › programming › what is model inheritance in django?
What Is Model Inheritance in Django?
July 19, 2023 - Once in a while, he explores the possibilities of Solidity and Web 3.0. He is popularly known as SuperheroJT. ... Model inheritance is a Django ORM feature that allows developers to create hierarchical relationships between database models.
Find elsewhere
Top answer
1 of 10
86

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)
2 of 10
65

No, it is not:

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 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.

🌐
Django Forum
forum.djangoproject.com › using django › using the orm
Design Advice: Multi-Table Inheritance vs. Abstract Base Classes - Using the ORM - Django Forum
April 7, 2024 - Hi, all. I’m currently designing a Django application that will serve as an interface for creating, managing, and practicing different types of flashcards, e.g., front and back, multiple-choice, etc. and am considering how to structure my models. Ideally, each type of flashcard will have its own model, e.g., FrontBackFlashcard, MultipleChoiceFlashcard, etc., and will share several basic attributes.
🌐
Django Forum
forum.djangoproject.com › using django › using the orm
Multi-table inheritance - how to use inherited id for relations? - Using the ORM - Django Forum
December 10, 2024 - In my project I had 2 different set of models for 2 different reports. TestsReport Values Then I had to create common Report model to unify and speed up some queries. First I used just standard explicit ForeignKey relations from TestsReport and MetricsReport to Report and it works fine, but it leads to 3 different set of IDs while just single report ID would be enough.
🌐
DEV Community
dev.to › zachtylr21 › model-inheritance-in-django-m0j
Model Inheritance in Django - DEV Community
August 24, 2020 - Multi-table inheritance is where the superclass, as well as each subclass, map to their own database tables. The shared fields are stored on the superclass table and the type-specific fields are stored on their respective tables. Each subclass table then has an extra column that contains the id of the corresponding row in the parent class table. In Django, the model classes might look something like this
🌐
Substack
astrocodecraft.substack.com › p › exploring-model-inheritance-in-django
Exploring Model Inheritance in Django: A Guide for Efficient Code Reuse
March 20, 2024 - Model inheritance is a powerful feature that allows developers to create modular and reusable code, significantly reducing redundancy and enhancing maintainability. This article delves into the three types of model inheritance in Django—m...
🌐
Medium
sambyalsandeep31.medium.com › django-model-inheritance-best-practices-147149d9721
Django Model Inheritance Best Practices | by Sandeep Singh Sambyal | Medium
July 7, 2021 - The point to note here is : 1. The model Player is abstract, so it cannot be registered with the admin. 2. No database table will be created for the abstract model. Pros: 1. As all common fields are in abstract class it saves us from typing them more than once. 2. No overhead of extra tables and joins as in multi-table inheritance.
Top answer
1 of 6
181

I actually want to know the difference between a model class that inherits from a django abstract class (Meta: abstract = True) and a plain Python class that inherits from say, 'object' (and not models.Model).

Django will only generate tables for subclasses of models.Model, so the former...

class User(models.Model):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

   class Meta:
       abstract = True

class Employee(User):
   title = models.CharField(max_length=255)

...will cause a single table to be generated, along the lines of...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(255) NOT NULL,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

...whereas the latter...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User):
   title = models.CharField(max_length=255)

...won't cause any tables to be generated.

You could use multiple inheritance to do something like this...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User, models.Model):
   title = models.CharField(max_length=255)

...which would create a table, but it will ignore the fields defined in the User class, so you'll end up with a table like this...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);
2 of 6
44

An abstract model creates a table with the entire set of columns for each subchild, whereas using "plain" Python inheritance creates a set of linked tables (aka "multi-table inheritance"). Consider the case in which you have two models:

class Vehicle(models.Model):
  num_wheels = models.PositiveIntegerField()


class Car(Vehicle):
  make = models.CharField(…)
  year = models.PositiveIntegerField()

If Vehicle is an abstract model, you'll have a single table:

app_car:
| id | num_wheels | make | year

However, if you use plain Python inheritance, you'll have two tables:

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

Where vehicle_id is a link to a row in app_vehicle that would also have the number of wheels for the car.

Now, Django will put this together nicely in object form so you can access num_wheels as an attribute on Car, but the underlying representation in the database will be different.


Update

To address your updated question, the difference between inheriting from a Django abstract class and inheriting from Python's object is that the former is treated as a database object (so tables for it are synced to the database) and it has the behavior of a Model. Inheriting from a plain Python object gives the class (and its subclasses) none of those qualities.

🌐
Readthedocs
django-model-utils.readthedocs.io › en › latest › managers.html
Model Managers — django-model-utils 0.0.post1+g66734d6f7 documentation
For instance, if you have a Place model with subclasses Restaurant and Bar, you may want to query all Places: nearby_places = Place.objects.filter(location='here') But when you iterate over nearby_places, you’ll get only Place instances back, even for objects that are “really” Restaurant or Bar. If you attach an InheritanceManager to Place, you can just call the select_subclasses() method on the InheritanceManager or any QuerySet from it, and the resulting objects will be instances of Restaurant or Bar:
🌐
Django way
djangoway.hashnode.dev › model-inheritance
Django models inheritance, customize Django models in admin page
October 20, 2023 - That is, the new table to be created can inherit the already existing columns from the already existing table. For instance, If you want to create a User table for your application and then you listed out the columns to be created as first_name, ...
🌐
Plain English
python.plainenglish.io › mastering-custom-managers-and-model-inheritance-in-django-c454010d677a
Mastering Custom Managers and Model Inheritance in Django | by Ewho Ruth | Python in Plain English
November 18, 2024 - Inherited Managers from Base Classes: Managers declared in base classes are automatically available in child classes. Django follows Python’s name resolution, so if a child class defines a manager with the same name as one in the parent, the ...
🌐
Django Forum
forum.djangoproject.com › using django › getting started
How does extending the user model work ? - Getting Started - Django Forum
February 18, 2024 - So i was learning about customizing the user model in Django and found two options to do it: One option is to use inheritance to extend the user model (abstract user class), so we can create another model called AppUser and this model should ...
Top answer
1 of 6
35

Summary

Django's proxy models provide the basis for Single Table Inheritance.

However, some effort is required to make it work.

Skip to the end for a re-usable example.

Background

Martin Fowler describes Single Table Inheritance (STI) as follows:

Single Table Inheritance maps all fields of all classes of an inheritance structure into a single table.

This is precisely what Django's proxy model inheritance does.

Note, that, according to this blog post from 2010, proxy models have been around since Django 1.1.

A "normal" Django model is a concrete model, i.e. it has a dedicated table in the database. There are two types of Django model that do not have dedicated database tables, viz. abstract models and proxy models:

  • Abstract models act as superclasses for concrete models. An abstract model can define fields, but it does not have a database table. The fields are only added to the database tables for its concrete subclasses.

  • Proxy models act as subclasses for concrete models. A proxy model cannot define new fields. Instead, it operates on the database table associated with its concrete superclass. In other words, a Django concrete model and its proxies all share a single table.

Django's proxy models provide the basis for Single Table Inheritance, viz. they allow different models to share a single table, and they allow us to define proxy-specific behavior on the Python side. However, Django's default object-relational mapping (ORM) does not provide all the behavior that would be expected, so a little customization is required. How much, that depends on your needs.

Let's build a minimal example, step by step, based on the simple data-model in the figure below:

Step 1: basic "proxy model inheritance"

Here's the content of models.py for a basic proxy inheritance implementation:

from django.db import models


class Party(models.Model):
    name = models.CharField(max_length=20)
    person_attribute = models.CharField(max_length=20)
    organization_attribute = models.CharField(max_length=20)


class Person(Party):
    class Meta:
        proxy = True


class Organization(Party):
    class Meta:
        proxy = True

Person and Organization are two types of parties.

Only the Party model has a database table, so all the fields are defined on this model, including any fields that are specific either to Person or to Organization.

Because Party, Person, and Organization all use the Party database table, we can define a single ForeignKey field to Party, and assign instances of any of the three models to that field, as implied by the inheritance relation in the figure. Note, that, without inheritance, we would need a separate ForeignKey field for each model.

For example, suppose we define an Address model as follows:

class Address(models.Model):
    party = models.ForeignKey(to=Party, on_delete=models.CASCADE)

We can then initialize an Address object using e.g. Address(party=person_instance) or Address(party=organization_instance).

So far, so good.

However, if we try to get a list of objects corresponding to a proxy model, using e.g. Person.objects.all(), we get a list of all Party objects instead, i.e. both Person objects and Organization objects. This is because the proxy models still use the model manager from the superclass (i.e. Party).

Step 2: add proxy model managers

To make sure that Person.objects.all() only returns Person objects, we need to assign a separate model manager that filters the Party queryset. To enable this filtering, we need a field that indicates which proxy model should be used for the object.

To be clear: creating a Person object implies adding a row to the Party table. The same goes for Organization. To distinguish between the two, we need a column to indicate if a row represents a Person or an Organization. For convenience and clarity, we add a field (i.e. column) called proxy_name, and use that to store the name of the proxy class.

So, enter the ProxyManager model manager and the proxy_name field:

from django.db import models


class ProxyManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(proxy_name=self.model.__name__)


class Party(models.Model):
    proxy_name = models.CharField(max_length=20)
    name = models.CharField(max_length=20)
    person_attribute = models.CharField(max_length=20)
    organization_attribute = models.CharField(max_length=20)

    def save(self, *args, **kwargs):
        self.proxy_name = type(self).__name__
        super().save(*args, **kwargs)


class Person(Party):
    class Meta:
        proxy = True

    objects = ProxyManager()


class Organization(Party):
    class Meta:
        proxy = True

    objects = ProxyManager()

Now the queryset returned by Person.objects.all() will only contain Person objects (and the same for Organization).

However, this does not work in the case of a ForeignKey relation to Party, as in Address.party above, because that will always return a Party instance, regardless of the value of the proxy_name field (also see docs). For example, suppose we create an address = Address(party=person_instance), then address.party will return a Party instance, instead of a Person instance.

Step 3: extend the Party constructor

One way to deal with the related-field issue is to extend the Party.__new__ method, so it returns an instance of the class specified in the 'proxy_name' field. The end result looks like this:

class Party(models.Model):
    PROXY_FIELD_NAME = 'proxy_name'
    
    proxy_name = models.CharField(max_length=20)
    name = models.CharField(max_length=20)
    person_attribute = models.CharField(max_length=20)
    organization_attribute = models.CharField(max_length=20)

    def save(self, *args, **kwargs):
        """ automatically store the proxy class name in the database """
        self.proxy_name = type(self).__name__
        super().save(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        party_class = cls
        try:
            # get proxy name, either from kwargs or from args
            proxy_name = kwargs.get(cls.PROXY_FIELD_NAME)
            if proxy_name is None:
                proxy_name_field_index = cls._meta.fields.index(
                    cls._meta.get_field(cls.PROXY_FIELD_NAME))
                proxy_name = args[proxy_name_field_index]
            # get proxy class, by name, from current module
            party_class = getattr(sys.modules[__name__], proxy_name)
        finally:
            return super().__new__(party_class)

Now address.party will actually return a Person instance if the proxy_name field is Person.

As a last step, we can make the whole thing re-usable:

Step 4: make it re-usable

To make our rudimentary Single-Table Inheritance implementation re-usable, we can use Django's abstract inheritance:

inheritance/models.py:

import sys
from django.db import models


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

    proxy_name = models.CharField(max_length=20)

    def save(self, *args, **kwargs):
        """ automatically store the proxy class name in the database """
        self.proxy_name = type(self).__name__
        super().save(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        """ create an instance corresponding to the proxy_name """
        proxy_class = cls
        try:
            field_name = ProxySuper._meta.get_fields()[0].name
            proxy_name = kwargs.get(field_name)
            if proxy_name is None:
                proxy_name_field_index = cls._meta.fields.index(
                    cls._meta.get_field(field_name))
                proxy_name = args[proxy_name_field_index]
            proxy_class = getattr(sys.modules[cls.__module__], proxy_name)
        finally:
            return super().__new__(proxy_class)


class ProxyManager(models.Manager):
    def get_queryset(self):
        """ only include objects in queryset matching current proxy class """
        return super().get_queryset().filter(proxy_name=self.model.__name__)

Then we can implement our inheritance structure as follows:

parties/models.py:

from django.db import models
from inheritance.models import ProxySuper, ProxyManager


class Party(ProxySuper):
    name = models.CharField(max_length=20)
    person_attribute = models.CharField(max_length=20)
    organization_attribute = models.CharField(max_length=20)


class Person(Party):
    class Meta:
        proxy = True

    objects = ProxyManager()


class Organization(Party):
    class Meta:
        proxy = True

    objects = ProxyManager()


class Placement(models.Model):
    party = models.ForeignKey(to=Party, on_delete=models.CASCADE)

More work may be required, depending on your needs, but I believe this covers some of the basics.

2 of 6
21

I think the OP is asking about Single-Table Inheritance as defined here:

Relational databases don't support inheritance, so when mapping from objects to databases we have to consider how to represent our nice inheritance structures in relational tables. When mapping to a relational database, we try to minimize the joins that can quickly mount up when processing an inheritance structure in multiple tables. Single Table Inheritance maps all fields of all classes of an inheritance structure into a single table.

That is, a single database table for a whole hierarchy of entity classes. Django does not support that kind of inheritance.

🌐
GitHub
github.com › GabLeRoux › django-multitable-inheritance
GitHub - GabLeRoux/django-multitable-inheritance: 💖django sample app to demonstrate model inheritance
As described in the following post Here's what happens when you use Multi Table Inheritance 🚀 · See multitable/models.py for code snippet. Generated using the awesome django-extensions, you should really use this ✌️
Author   GabLeRoux