[Fixed]-Tricky model inheritance – Django

15👍

Multiple inheritance doesn’t work well with databases (and your Django models do need to map down to a database in the end), and inheritance is often a bad way to model “roles” (because people’s roles do change). I would have Singer, Bassist and Ninja as “roles”, not as subclasses of Person, and connect them via foreign keys:

class Singer(models.Model):
    person = models.ForeignKey('Person')
    # ...

class Person(models.Model):
    # ...

3👍

In principle you can do something like the following:

class Role(models.Model):       
     ......

class Ninja(Role):
     .......

class Person(models.Model):
      roles = models.ManyToManyField(Role)

But then you run in to the problem that Person.roles.objects.all() can only give you instances of Role. So you need a method to casts each instance of Role to the a suitable subclass such as Ninja or Pirate. Here is a link to a thread that discusses this problem.

http://groups.google.com/group/django-users/browse_thread/thread/f4241bc16455f92d/7268c3f7bca6b046

So in short Alex and Stefano have given more useful answers than me.

👤niels

2👍

I agree about the roles solution, as depicted by Alex. What you have is not different subclasses of persons. You have different roles a person can have.

But I hear you say: “hey, the ninja can have a property “numberOfStars”, while a singer can have a property “highestNote”. Same as for the interface: a ninja can have the method throwStar() and disappear(), while a singer can have sing() and getWasted(), and the bass player can have goFunky() and slapPop()

What you have here is a case where your data model needs a very loose schema. So loose that, in fact, you have no schema at all. If the singer decides to take the bass and improvise a tune, that’s fine. If he wants to act as a ninja, and you call throwStar, it will return an error, because he has no stars, but you could in principle, assign stars to a singer and make him throw stars.

What you are venturing in is the world of ontologies, rather than schemas. You have a resource, which is “something” and this something can be some type, have some properties, etc. Presence of some properties can infer the type, or presence of some type can infer other types. You cannot describe this information easily with the simple django data model. What you would need is a context-aware, inferenced graph store, such as AllegroGraph, or implement your hacked up solution using rdflib.

1👍

You could make all your professions (Ninja, Bassist….) inherit from Person in the models, and then use the function isinstance in the backend code to distinguish between the professions of a Person.

👤German

Leave a comment