4
votes

This isn't really specific to django.

One can model

Place (with location, name, and other common attributes)
 - Restaurant  (menu..)
 - ConcertHall  (hall size..)
  1. in two separate tables and let each one hold all the fields they need. (in django world, this is called abstract inheritance)
  2. in three tables, where one holds the common fields and the other two has their own unique fields. (multi-table inheritance in django)

The authors of book Two scoops of Django 1.8 strongly advise against using multi-table inheritance.

Say you want to query places based on it's location and paginate the results (It doesn't have to be a location, can be any other common attribute we want to filter on)

I can see how I can achieve it using Multi-table inheritance.

select place.id from place LEFT OUTER JOIN "restaurant" on ( restuarant.id=place.id) LEFT OUTER JOIN "concerthall" on ( concerthall.id=place.id) where ... order by distance

Is it feasible to do it with abstract inheritance?

2
Just a link to this similar SO question. - djvg

2 Answers

5
votes

According to Django documentation: Model inheritance:

The only decision you have to make is whether you want the parent models to be models in their own right (with their own database tables), or if the parents are just holders of common information that will only be visible through the child models.

I think both possibilities are just tools, equally good tools and it just depends on your use case for their appropriateness. Surely there are specific things to consider for both approaches, and conceptually sometimes multi-table inheritance may be more difficult to comprehend, but other than that this topic just turns to become opinionated.

If you need a single queryset for both models, then it is logical that you consider multi-table inheritance rather than abstract models, because otherwise you would need to get into combining two querysets into one, most probably by using lists as this relevant answer suggests, but you would definitely lose ORM functionality.

2
votes

It depends on your usecases, but Django ihave a good Database ORM for Database Normalized table structure.

Keeping the base fields in a model and keeping the specifics on another is the best approach in Database Normalization logic because you may have query on different tables and that is not a desired situation. Django relations and reverse relations offers you what you need at this point.

An Example based on yours considering you are using Multi Table Inheritance:

Place.objects.filter(location=x)
Place.objects.filter(location=x, Q(Q(concerthall__hallsize__gt=y)| Q(restaurant__menu=z)))
Place.objects.filter(location=x, concerthall__id__isnull=True)

First will return you all Restaurants and Concert Halls in x.

Second will return you All places which are Concert Halls with hall sizes greater than y or Restaurants with menu z.

Last one is a super magic query that will return you all places in location x which is not a Concert Hall. That is useful when you have many Models inheriting from Place. You can use <model_name>__id for including/excluding tables according to your needs.

You can built great JOINS including many tables and do stick to Database Normalization rules while doing this. You will keep your related data in one place and avoid possible data integrity problems.