Welcome | Get started | Dive into Lino | Contribute | Topics | Reference | More

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*, *Bert*
 2    The Chopping Shack    *Anne*
 3    The Abacus Well       *Claude*
 4    The Olive Lounge      *Ernie*
 5    The Autumn Bite       *Anne*
 6    The Private Mission   *Claude*
 7    Nova                  *Ernie*
 8    Babylon               *Anne*
 9    Blossoms              *Claude*
 10   Whisperwind           *Ernie*
 11   Catch                 *Anne*
==== ===================== ================
>>> rt.show("app.Restaurants")
==== ===================== ================= ========== ========
 ID   name                  serves hot dogs   owners     cooks
---- --------------------- ----------------- ---------- --------
 2    The Chopping Shack    No                *Anne*     *Bert*
 3    The Abacus Well       No                *Claude*   *Dirk*
 4    The Olive Lounge      No                *Ernie*    *Fred*
 5    The Autumn Bite       No                *Anne*     *Bert*
 6    The Private Mission   No                *Claude*   *Dirk*
 7    Nova                  No                *Ernie*    *Fred*
 8    Babylon               No                *Anne*     *Bert*
 9    Blossoms              No                *Claude*   *Dirk*
 10   Whisperwind           No                *Ernie*    *Fred*
 11   Catch                 No                *Anne*     *Bert*
==== ===================== ================= ========== ========