While the existing `ManyToManyField` is suitable for basic relationships, some projects find need to tie objects together along with some information about their relationship. The common example is the role an actor played in a movie, but it could be used for many other things, including what "base" a dating couple has gotten to, for instance. For these cases, the common recommendation is to simply create an intermediary model with `ForeignKey`s to each of the connected models, along with any extra fields that are appropriate for the relationship. In the Hollywood example, something like this: {{{ #!python class Actor(models.Model): name = models.CharField(maxlength=255) class Film(models.Model): title = models.CharField(maxlength=255) actors = models.ManyToManyField(Actor) }}} would become something like this instead, with the `role` field added: {{{ #!python class Actor(models.Model): name = models.CharField(maxlength=255) class Film(models.Model): title = models.CharField(maxlength=255) class Role(models.Model): actor = models.ForeignKey(Actor, related_name='roles') film = models.ForeignKey(Film, related_name='roles') role = models.CharField(maxlength=255) }}} Unfortunately, the database API then goes from this: {{{ #!python >>> for actor in film.actors.all(): ... print actor.name Graham Chapman Terry Gilliam John Cleese Eric Idle }}} to this: {{{ #!python >>> for role in film.roles.all(): ... print '%s played %s' % (role.actor.name, role.role) Graham Chapman played King Arthur Terry Gilliam played Sir Bors John Cleese played Sir Lancelot the Brave Eric Idle played Sir Robin the Not-Quite-So-Brave-as-Sir Launcelot }}} While programmers may not have a problem with this change, it is very counter-intuitive for template authors who may not have (nor should they need) an intimate understanding of how relational databases work. I'd like to propose an alternative, using a custom manager for these intermediary models, that will enable a more natural API. By simply adding one line and renaming the `related_name`s: {{{ #!python class Actor(models.Model): name = models.CharField(maxlength=255) class Film(models.Model): title = models.CharField(maxlength=255) class Role(models.Model): actor = models.ForeignKey(Actor, related_name='films') film = models.ForeignKey(Film, related_name='actors') role = models.CharField(maxlength=255) objects = models.ManyToManyManager() }}} we could get a much more intuitive API: {{{ #!python >>> for actor in film.actors.all(): ... print '%s played %s' % (actor.name, actor.role) Graham Chapman played King Arthur Terry Gilliam played Sir Bors John Cleese played Sir Lancelot the Brave Eric Idle played Sir Robin the Not-Quite-So-Brave-as-Sir Launcelot }}} This would work just as well in both directions: {{{ #!python >>> for film in john.films.all(): ... print '%s in %s' % (film.role, film.title) Sir Lancelot the Brave in Monty Python and the Holy Grail Sir Nicholas de Mimsy-Porpington in Harry Potter and the Sorceror's Stone }}} Ideally, this API would also extend the `add` method of the manager, allowing it to take keyword attributes for the relationship meta-data: {{{ #!python >>> film = Film.objects.create(title='And Now for Something Completely Different') >>> john.films.add(film, role='Sir George Head') >>> for film in john.films.all(): ... print '%s in %s' % (film.role, film.title) Sir Lancelot the Brave in Monty Python and the Holy Grail Sir Nicholas de Mimsy-Porpington in Harry Potter and the Sorceror's Stone Sir George Head in And Now for Something Completely Different }}} And without the intermediary model, there's need for an `update` function on the manager, which would handle modifying the meta-data: {{{ #!python >>> film.actors.update(john, role='Mungo the Cook') }}}