diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 6629289b05..5a173b6fa5 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -1,3 +1,5 @@ +import copy + from django.db import connection, transaction from django.db.models import signals, get_model from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class @@ -108,6 +110,8 @@ class RelatedField(object): add_lazy_relation(cls, self, other) else: self.do_related_class(other, cls) + if not cls._meta.abstract and self.rel.related_name: + self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()} def set_attributes_from_rel(self): self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name) @@ -149,9 +153,10 @@ class RelatedField(object): raise TypeError, "Related Field has invalid lookup: %s" % lookup_type def _get_related_query_name(self, opts): - # This method defines the name that can be used to identify this related object - # in a table-spanning query. It uses the lower-cased object_name by default, - # but this can be overridden with the "related_name" option. + # This method defines the name that can be used to identify this + # related object in a table-spanning query. It uses the lower-cased + # object_name by default, but this can be overridden with the + # "related_name" option. return self.rel.related_name or opts.object_name.lower() class SingleRelatedObjectDescriptor(object): diff --git a/docs/model-api.txt b/docs/model-api.txt index 5502bd51eb..dd9fe8bdf2 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -886,6 +886,10 @@ relationship should work. All are optional: `related objects documentation`_ for a full explanation and example. + If using this in an `abstract base class`_, be + sure to read the `extra notes`_ in that section + about ``related_name``. + ``to_field`` The field on the related object that the relation is to. By default, Django uses the primary key of the related object. @@ -893,6 +897,8 @@ relationship should work. All are optional: .. _`Database API reference`: ../db-api/ .. _related objects documentation: ../db-api/#related-objects +.. _abstract base class: `Abstract base classes`_ +.. _extra notes: `Be careful with related_name`_ Many-to-many relationships ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2146,6 +2152,39 @@ abstract base class. For example, including ``db_table`` would mean that all the child classes (the ones that don't specify their own ``Meta``) would use the same database table, which is almost certainly not what you want. +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. This would normally cause a problem in abstract base classes, since the +fields on this class are included into each of the child classes, with exactly +the same values for the attributes (including ``related_name``) each time. + +To work around this problem, when you are using ``related_name`` in an +abstract base class (only), part of the name should be the string +``'%(class)s'``. This is replaced by the lower-cased name of the child class +that the field is used in. Since each class has a different name, each related +name will end up being different. For example:: + + class Base(models.Model): + m2m = models.ManyToMany(OtherModel, related_name="%(class)s_related") + + class Meta: + abstract = True + + class ChildA(Base): + pass + + class ChildB(Base): + pass + +The reverse name of the ``ChildA.m2m`` field will be ``childa_related``, +whilst the reverse name of the ``ChildB.m2m`` field will be +``childb_related``. It is up to you how you use the ``'%(class)s'`` portion to +construct your related name, but if you forget to use it, Django will raise +errors when you validate your models (or run ``syncdb``). + Multi-table inheritance -----------------------