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
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.