djangoinheritancemodelmulti-table-inheritance

Effectively use Multi-table inheritance (one-to-one relationships)


I need several models that inherit from a base class in a one-to-one relationship. In keeping with the Django example:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

class Garage(Place):
    car_brands_serviced = Models.ManyToManyField(Brands)

class Boutique(Place):
    for = Models.ChoiceField(choices=( ("m", "men"), ("w", "women"), ("k","kids"))

# etc

Now how do I effectively distinguish between the various types of Places when I iterated them in a template (or view function)? Right now, I only see this solution (if I want to iterate over Places, rather than child models individually):

for place in Place.objects.all():
    try:
        r = place.restaurant
        # Do restaurant stuff here
    except ObjectDoesNotExist:
        try:
            g = place.garage
            # Do garage stuff here
        except ObjectDoesNotExist:
            try:
                b = place.boutique
                # Do boutique stuff here
            except ObjectDoesNotExist:
                # Place is not specified

Not even sure how that would translate to a template, but this code seems very wrong and inefficient.

As an escape, I guess you could make a choicefield in Place to track which child model is related, but that equates to dangerous denormalisation.

Am I somehow overthinking this? How do you do this?


Solution

  • Could it be something simple like:

    models.py:

    from django.db import models
    
    class Place(models.Model):
        name = models.CharField(max_length=50)
    
    class Restaurant(Place):
        serves_hot_dogs = models.BooleanField(default=False)
        serves_pizza = models.BooleanField(default=False)
        is_restaurant = True
    
    class Garage(Place):
        car_brands_serviced = Models.ManyToManyField(Brands)
        is_garage = True
    

    A template could work like this – template.html:

    {% for place in places %}
     {% if place.is_restaurant %}
      <!-- Restaurant Stuff -->
     {% elif place.is_garage %}
      <!-- Garage Stuff -->
     {% endif %}
    {% endfor %}