I'm building a Movie database. The thing is each movie can have many producers and many directors. The directors can be either persons or collectives, and the producers might be persons, collectives or institutions (or a mixture of all these things). I also want to store different information for these kinds of entities (persons, collectives and institutions). Furthermore, I need:
- To have order (director1, director2) is different from (director2, director1)
- The admin to be able to handle producer/director adding, modifying, etc. from the Movie module.
To organize my models I've thought of having a generic m2m relation (inspired in this answer) --only for directors, to simplify:
class Movie(models.Model):
name = models.CharField(max_length=100)
# etc...
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
director_of = GenericRelation('Directorship')
class Collective(models.Model):
name = models.CharField(max_length=100)
number_of_participants = models.IntegerField()
director_of = GenericRelation('Directorship')
class Directorship(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='directors')
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
order = models.PositiveIntegerField()
The problem with this solution is that the Movie admin with a Directorship inline looks awful:
I could customize the admin form to display a specific ModelForm depending on the choice of the first combobox, but that looks like an awful lot of work (see e.g. this)
The other option I considered would be to give the intermediary model two ForeignKeys (one to Person and one to Collective) and have it be the 'through' model of two standard m2m relations on Movie. I'd also have to override save to ensure that one and only one of those ForeignKeys is non-Null:
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Collective(models.Model):
name = models.CharField(max_length=100)
number_of_participants = models.IntegerField()
class Movie(models.Model):
name = models.CharField(max_length=100)
person_directors = models.ManyToManyField(Person, through='Directorship', blank=True)
collective_directors = models.ManyToManyField(Collective, through='Directorship', blank=True)
# etc...
class Directorship(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
collective = models.ForeignKey(Collective, on_delete=models.CASCADE, blank=True, null=True)
order = models.PositiveIntegerField()
def save(*args, **kwargs):
# etc...
What I dont know here is if using the same model as the through model of two different m2m relations will work. I'm also wondering if I could somehow define a @property directors, that gives me a queryset of every person_director and collective_director ordered by the .order attribute on Directorship.
Are any of these solutions on the right track? Is there another standard way of solving this that I'm not aware of?