Skip to content

Commit 2b42663

Browse files
committed
queryset-refactor: Added a way to specify the related_name attribute on
abstract base classes. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7432 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent b114fec commit 2b42663

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

django/db/models/fields/related.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import copy
2+
13
from django.db import connection, transaction
24
from django.db.models import signals, get_model
35
from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
@@ -108,6 +110,8 @@ def contribute_to_class(self, cls, name):
108110
add_lazy_relation(cls, self, other)
109111
else:
110112
self.do_related_class(other, cls)
113+
if not cls._meta.abstract and self.rel.related_name:
114+
self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()}
111115

112116
def set_attributes_from_rel(self):
113117
self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
@@ -149,9 +153,10 @@ def pk_trace(value):
149153
raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
150154

151155
def _get_related_query_name(self, opts):
152-
# This method defines the name that can be used to identify this related object
153-
# in a table-spanning query. It uses the lower-cased object_name by default,
154-
# but this can be overridden with the "related_name" option.
156+
# This method defines the name that can be used to identify this
157+
# related object in a table-spanning query. It uses the lower-cased
158+
# object_name by default, but this can be overridden with the
159+
# "related_name" option.
155160
return self.rel.related_name or opts.object_name.lower()
156161

157162
class SingleRelatedObjectDescriptor(object):

docs/model-api.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,13 +886,19 @@ relationship should work. All are optional:
886886
`related objects documentation`_ for a full
887887
explanation and example.
888888

889+
If using this in an `abstract base class`_, be
890+
sure to read the `extra notes`_ in that section
891+
about ``related_name``.
892+
889893
``to_field`` The field on the related object that the relation
890894
is to. By default, Django uses the primary key of
891895
the related object.
892896
======================= ============================================================
893897

894898
.. _`Database API reference`: ../db-api/
895899
.. _related objects documentation: ../db-api/#related-objects
900+
.. _abstract base class: `Abstract base classes`_
901+
.. _extra notes: `Be careful with related_name`_
896902

897903
Many-to-many relationships
898904
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2146,6 +2152,39 @@ abstract base class. For example, including ``db_table`` would mean that all
21462152
the child classes (the ones that don't specify their own ``Meta``) would use
21472153
the same database table, which is almost certainly not what you want.
21482154

2155+
Be careful with ``related_name``
2156+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2157+
2158+
If you are using the ``related_name`` attribute on a ``ForeignKey`` or
2159+
``ManyToManyField``, you must always specify a *unique* reverse name for the
2160+
field. This would normally cause a problem in abstract base classes, since the
2161+
fields on this class are included into each of the child classes, with exactly
2162+
the same values for the attributes (including ``related_name``) each time.
2163+
2164+
To work around this problem, when you are using ``related_name`` in an
2165+
abstract base class (only), part of the name should be the string
2166+
``'%(class)s'``. This is replaced by the lower-cased name of the child class
2167+
that the field is used in. Since each class has a different name, each related
2168+
name will end up being different. For example::
2169+
2170+
class Base(models.Model):
2171+
m2m = models.ManyToMany(OtherModel, related_name="%(class)s_related")
2172+
2173+
class Meta:
2174+
abstract = True
2175+
2176+
class ChildA(Base):
2177+
pass
2178+
2179+
class ChildB(Base):
2180+
pass
2181+
2182+
The reverse name of the ``ChildA.m2m`` field will be ``childa_related``,
2183+
whilst the reverse name of the ``ChildB.m2m`` field will be
2184+
``childb_related``. It is up to you how you use the ``'%(class)s'`` portion to
2185+
construct your related name, but if you forget to use it, Django will raise
2186+
errors when you validate your models (or run ``syncdb``).
2187+
21492188
Multi-table inheritance
21502189
-----------------------
21512190

0 commit comments

Comments
 (0)