Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
Is MTI a bad thing?¶
If you believe that multi-table inheritance “is a bad thing”, then this example
shows how you would solve the same real-world problem as
lino_book.projects.mti
by using OneToOneFields instead of MTI.
The database models¶
Here is the models.py
file used for this example.
We have a table of Places, some of them are Restaurants, some are Pubs, and some are neither Pub nor Restaurant.
# -*- coding: UTF-8 -*-
# Copyright 2015-2020 Rumma & Ko Ltd
# License: GNU Affero General Public License v3 (see file COPYING for details)
from django.db import models
from lino.api import dd
class Person(dd.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Place(dd.Model):
name = models.CharField(max_length=50)
owners = models.ManyToManyField(Person, related_name="owned_places")
ceo = dd.ForeignKey(Person, related_name="managed_places")
def __str__(self):
if self.get_restaurant():
if self.get_bar():
what = "Restaurant & Bar "
else:
what = "Restaurant "
elif self.get_bar():
what = "Bar "
else:
what = ''
if self.pk is None:
return self.name
return "%s %s(ceo=%s,owners=%s)" % (
self.name, what, self.ceo, ','.join(
[str(o) for o in self.owners.all()]))
def get_restaurant(self):
try:
return self.restaurant
except Restaurant.DoesNotExist:
return None
def get_bar(self):
try:
return self.bar
except Bar.DoesNotExist:
return None
class Bar(dd.Model):
place = dd.OneToOneField(Place)
serves_alcohol = models.BooleanField(default=True)
def __str__(self):
if self.serves_alcohol:
return self.place.name
return "%s (no alcohol)" % self.place.name
class Restaurant(dd.Model):
place = dd.OneToOneField(Place)
serves_hot_dogs = models.BooleanField(default=False)
cooks = models.ManyToManyField(Person)
def __str__(self):
if self.pk is None:
return self.place.name
return "%s (cooks=%s)" % (self.place.name, ','.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 *
The demo data¶
Here are the Persons who act in our story:
>>> rt.show('app.Persons')
========
name
--------
Anne
Bert
Claude
Dirk
Ernie
Fred
========
>>> rt.show('app.Places')
==== ===================== ======== ============================
ID name person owners
---- --------------------- -------- ----------------------------
1 Bert's pub Anne `Anne <…>`__, `Bert <…>`__
2 The Chopping Shack Bert `Claude <…>`__
3 The Abacus Well Ernie `Fred <…>`__
4 The Olive Lounge Bert `Claude <…>`__
5 The Autumn Bite Ernie `Fred <…>`__
6 The Private Mission Bert `Claude <…>`__
7 Nova Ernie `Fred <…>`__
8 Babylon Bert `Claude <…>`__
9 Blossoms Ernie `Fred <…>`__
10 Whisperwind Bert `Claude <…>`__
11 Catch Ernie `Fred <…>`__
==== ===================== ======== ============================
>>> rt.show('app.Restaurants')
==== ========================================================= ================= ==============
ID place serves hot dogs cooks
---- --------------------------------------------------------- ----------------- --------------
1 The Chopping Shack Restaurant (ceo=Bert,owners=Claude) No `Dirk <…>`__
2 The Abacus Well Restaurant (ceo=Ernie,owners=Fred) No `Anne <…>`__
3 The Olive Lounge Restaurant (ceo=Bert,owners=Claude) No `Dirk <…>`__
4 The Autumn Bite Restaurant (ceo=Ernie,owners=Fred) No `Anne <…>`__
5 The Private Mission Restaurant (ceo=Bert,owners=Claude) No `Dirk <…>`__
6 Nova Restaurant (ceo=Ernie,owners=Fred) No `Anne <…>`__
7 Babylon Restaurant (ceo=Bert,owners=Claude) No `Dirk <…>`__
8 Blossoms Restaurant (ceo=Ernie,owners=Fred) No `Anne <…>`__
9 Whisperwind Restaurant (ceo=Bert,owners=Claude) No `Dirk <…>`__
10 Catch Restaurant (ceo=Ernie,owners=Fred) No `Anne <…>`__
==== ========================================================= ================= ==============