Abstract base classes and backward relations

In Django, when you create a relation using ForeignKey or a ManyToManyField, a corresponding backward relation is automatically created for you. This backward relation gets a reasonable default name. If you’d rather use a different name, you can specify one with the related_name parameter.

But what if you don’t need or want the backward relation in the first place? The online documentation has advice to offer: « If you’d prefer Django didn’t create a backwards relation, set related_name to '+'. »

This works as advertised for plain models, but, at least in Django 1.3, it breaks with abstract base classes. The following code will not pass validation if more than one class inherits from the abstract base:

# This is broken as of Django 1.3
class AbstractBaseClass(models.Model):
    readers = ForeignKey('Reader', related_name='+')
    class Meta:
        abstract = True

The reason for the validation failure is found in the online documentation, under the very appropriate heading of Be careful with related_name: «If you are using the related_name attribute on a ForeignKey or ManyToManyField, you must always specify a unique reverse name for the field. »

Clearly, something is missing, as you can either specify a unique reverse name (using the substitution tags specifically introduced for abstract base classes), or set the name to '+'. Some digging around reveals that any name ending in + will do the trick, so you can indeed specify a unique reverse name for the relation and at the same time get rid of it. The following code will pass validation:

# The proper way to do it in Django 1.3
class AbstractBaseClass(models.Model):
    readers = ForeignKey('Reader',
            related_name='readable_%(app_label)s_%(class)s_set+')
    class Meta:
        abstract = True

Of course, you should not have to come up with a unique name for a relation that you don’t want created.

Indeed, using a special value for the name of an item to signal that you don’t want the item to be created in the first place is an example of adopting a clever hack instead of proper design. A separate boolean field would not only get the job done, but it would also avoid needless programmer surprises.

In real life, tawmas goes by the name of Tommaso R. Donnarumma. When asked, he describes himself as an Italian in Québec; a passionate programmer who has also been a project manager and a sysadmin; an Ubuntu user; an avid photographer; a lover of books, Baroque music, jazz, red wines, white beers; a gamer; an incurable curious.

2 thoughts on “Abstract base classes and backward relations

Leave a Reply

Your email address will not be published. Required fields are marked *