Multi-table inheritance (MTI)

This document describes the lino_book.projets.mti demo project, an application used for testing and explaining Multi-table inheritance.

The example database

Here is the models.py file used for this example. This is classical Django know-how: Restaurant inherits from Place, and Place is not abstract. That's what Django calls multi table inheritance.

# Copyright 2010-2020 Rumma & Ko Ltd
# License: GNU Affero General Public License v3 (see file COPYING for details)

from lino.api import dd
from django.db import models
from lino.mixins.polymorphic import Polymorphic


class Person(models.Model):

    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name



class Place(Polymorphic):

    name = models.CharField(max_length=50)
    owners = models.ManyToManyField(Person)

    def __str__(self):
        if self.pk is None:
            return self.name
        return "%s (owners=%s)" % (
            self.name,
            ', '.join([str(o) for o in self.owners.all()]))



class Restaurant(Place):

    serves_hot_dogs = models.BooleanField(default=False)
    cooks = models.ManyToManyField(Person)

    def __str__(self):
        if self.pk is None:
            return self.name
        return "%s (owners=%s, cooks=%s)" % (
            self.name,
            ', '.join([str(o) for o in self.owners.all()]),
            ', '.join([str(o) for o in self.cooks.all()]))



class Visit(models.Model):

    allow_cascaded_delete = ['place']
    person = dd.ForeignKey(Person)
    place = dd.ForeignKey(Place)
    purpose = models.CharField(max_length=50)

    def __str__(self):
        return "%s visit by %s at %s" % (
            self.purpose, self.person, self.place.name)



class Meal(models.Model):

    allow_cascaded_delete = ['restaurant']
    person = dd.ForeignKey(Person)
    restaurant = dd.ForeignKey(Restaurant)
    what = models.CharField(max_length=50)

    def __str__(self):
        return "%s eats %s at %s" % (
            self.person, self.what, self.restaurant.name)


from .ui import *
>>> rt.show("app.Persons")
========
 name
--------
 Anne
 Bert
 Claude
 Dirk
 Ernie
 Fred
========
>>> rt.show("app.Places")
==== ===================== ======================================
 ID   name                  owners
---- --------------------- --------------------------------------
 1    Bert's pub            `Anne <Detail>`__, `Bert <Detail>`__
 2    The Chopping Shack    `Anne <Detail>`__
 3    The Abacus Well       `Claude <Detail>`__
 4    The Olive Lounge      `Ernie <Detail>`__
 5    The Autumn Bite       `Anne <Detail>`__
 6    The Private Mission   `Claude <Detail>`__
 7    Nova                  `Ernie <Detail>`__
 8    Babylon               `Anne <Detail>`__
 9    Blossoms              `Claude <Detail>`__
 10   Whisperwind           `Ernie <Detail>`__
 11   Catch                 `Anne <Detail>`__
==== ===================== ======================================
>>> rt.show("app.Restaurants")
==== ===================== ================= ===================== ===================
 ID   name                  serves hot dogs   owners                cooks
---- --------------------- ----------------- --------------------- -------------------
 2    The Chopping Shack    No                `Anne <Detail>`__     `Bert <Detail>`__
 3    The Abacus Well       No                `Claude <Detail>`__   `Dirk <Detail>`__
 4    The Olive Lounge      No                `Ernie <Detail>`__    `Fred <Detail>`__
 5    The Autumn Bite       No                `Anne <Detail>`__     `Bert <Detail>`__
 6    The Private Mission   No                `Claude <Detail>`__   `Dirk <Detail>`__
 7    Nova                  No                `Ernie <Detail>`__    `Fred <Detail>`__
 8    Babylon               No                `Anne <Detail>`__     `Bert <Detail>`__
 9    Blossoms              No                `Claude <Detail>`__   `Dirk <Detail>`__
 10   Whisperwind           No                `Ernie <Detail>`__    `Fred <Detail>`__
 11   Catch                 No                `Anne <Detail>`__     `Bert <Detail>`__
==== ===================== ================= ===================== ===================