1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

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
This commit is contained in:
Malcolm Tredinnick 2008-04-16 08:09:46 +00:00
parent b114fecfe4
commit 2b426635aa
2 changed files with 47 additions and 3 deletions

View File

@ -1,3 +1,5 @@
import copy
from django.db import connection, transaction from django.db import connection, transaction
from django.db.models import signals, get_model from django.db.models import signals, get_model
from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class 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) add_lazy_relation(cls, self, other)
else: else:
self.do_related_class(other, cls) 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): def set_attributes_from_rel(self):
self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name) 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 raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
def _get_related_query_name(self, opts): def _get_related_query_name(self, opts):
# This method defines the name that can be used to identify this related object # This method defines the name that can be used to identify this
# in a table-spanning query. It uses the lower-cased object_name by default, # related object in a table-spanning query. It uses the lower-cased
# but this can be overridden with the "related_name" option. # object_name by default, but this can be overridden with the
# "related_name" option.
return self.rel.related_name or opts.object_name.lower() return self.rel.related_name or opts.object_name.lower()
class SingleRelatedObjectDescriptor(object): class SingleRelatedObjectDescriptor(object):

View File

@ -886,6 +886,10 @@ relationship should work. All are optional:
`related objects documentation`_ for a full `related objects documentation`_ for a full
explanation and example. 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 ``to_field`` The field on the related object that the relation
is to. By default, Django uses the primary key of is to. By default, Django uses the primary key of
the related object. the related object.
@ -893,6 +897,8 @@ relationship should work. All are optional:
.. _`Database API reference`: ../db-api/ .. _`Database API reference`: ../db-api/
.. _related objects documentation: ../db-api/#related-objects .. _related objects documentation: ../db-api/#related-objects
.. _abstract base class: `Abstract base classes`_
.. _extra notes: `Be careful with related_name`_
Many-to-many relationships 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 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. 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 Multi-table inheritance
----------------------- -----------------------