summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2015-09-20 17:51:25 +0200
committerAymeric Augustin <aymeric.augustin@m4x.org>2015-09-21 22:20:42 +0200
commite542e81b39e8610b70cf1d68f95ece0279028765 (patch)
tree92da80cf497dbab79d05d5ec050927bfe107c153
parent2409a4241a07bcdb1be4f3c99bf1aacc87189ebf (diff)
Renamed descriptor classes for related objects.
The old names were downright confusing. Some seemed to mean the opposite of what the class actually did. The new names follow a consistent nomenclature: (Forward|Reverse)(ManyToOne|OneToOne|ManyToMany)Descriptor. I mentioned combinations that do not exist in the docstring in order to help people who would search for them in the code base.
-rw-r--r--django/contrib/contenttypes/fields.py11
-rw-r--r--django/db/models/fields/related.py14
-rw-r--r--django/db/models/fields/related_descriptors.py63
-rw-r--r--tests/foreign_object/models/article.py5
-rw-r--r--tests/foreign_object/models/empty_join.py10
-rw-r--r--tests/generic_relations/tests.py2
-rw-r--r--tests/many_to_many/tests.py4
-rw-r--r--tests/many_to_one_null/tests.py2
-rw-r--r--tests/prefetch_related/tests.py4
-rw-r--r--tests/schema/fields.py4
10 files changed, 61 insertions, 58 deletions
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index 1cd2fc0fa6..9d5c47da9a 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -9,7 +9,7 @@ from django.db import DEFAULT_DB_ALIAS, connection, models, router, transaction
from django.db.models import DO_NOTHING, signals
from django.db.models.base import ModelBase, make_foreign_order_accessors
from django.db.models.fields.related import (
- ForeignObject, ForeignObjectRel, ForeignRelatedObjectsDescriptor,
+ ForeignObject, ForeignObjectRel, ReverseManyToOneDescriptor,
lazy_related_operation,
)
from django.db.models.query_utils import PathInfo
@@ -24,8 +24,7 @@ class GenericForeignKey(object):
``object_id`` fields.
This class also doubles as an accessor to the related object (similar to
- ReverseSingleRelatedObjectDescriptor) by adding itself as a model
- attribute.
+ ForwardManyToOneDescriptor) by adding itself as a model attribute.
"""
# Field flags
@@ -381,7 +380,7 @@ class GenericRelation(ForeignObject):
kwargs['virtual_only'] = True
super(GenericRelation, self).contribute_to_class(cls, name, **kwargs)
self.model = cls
- setattr(cls, self.name, ReverseGenericRelatedObjectsDescriptor(self.remote_field))
+ setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))
# Add get_RELATED_order() and set_RELATED_order() methods if the model
# on the other end of this relation is ordered with respect to this.
@@ -430,7 +429,7 @@ class GenericRelation(ForeignObject):
})
-class ReverseGenericRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
+class ReverseGenericManyToOneDescriptor(ReverseManyToOneDescriptor):
"""
Accessor to the related objects manager on the one-to-many relation created
by GenericRelation.
@@ -440,7 +439,7 @@ class ReverseGenericRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
class Post(Model):
comments = GenericRelation(Comment)
- ``post.comments`` is a ReverseGenericRelatedObjectsDescriptor instance.
+ ``post.comments`` is a ReverseGenericManyToOneDescriptor instance.
"""
@cached_property
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index b5cfbb1541..6b563360f5 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -25,8 +25,8 @@ from . import (
PositiveSmallIntegerField,
)
from .related_descriptors import (
- ForeignRelatedObjectsDescriptor, ManyRelatedObjectsDescriptor,
- ReverseSingleRelatedObjectDescriptor, SingleRelatedObjectDescriptor,
+ ForwardManyToOneDescriptor, ManyToManyDescriptor,
+ ReverseManyToOneDescriptor, ReverseOneToOneDescriptor,
)
from .related_lookups import (
RelatedExact, RelatedGreaterThan, RelatedGreaterThanOrEqual, RelatedIn,
@@ -432,7 +432,7 @@ class ForeignObject(RelatedField):
one_to_one = False
requires_unique_target = True
- related_accessor_class = ForeignRelatedObjectsDescriptor
+ related_accessor_class = ReverseManyToOneDescriptor
rel_class = ForeignObjectRel
def __init__(self, to, on_delete, from_fields, to_fields, rel=None, related_name=None,
@@ -684,7 +684,7 @@ class ForeignObject(RelatedField):
def contribute_to_class(self, cls, name, virtual_only=False):
super(ForeignObject, self).contribute_to_class(cls, name, virtual_only=virtual_only)
- setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
+ setattr(cls, self.name, ForwardManyToOneDescriptor(self))
def contribute_to_related_class(self, cls, related):
# Internal FK's - i.e., those with a related name ending with '+' -
@@ -974,7 +974,7 @@ class OneToOneField(ForeignKey):
one_to_many = False
one_to_one = True
- related_accessor_class = SingleRelatedObjectDescriptor
+ related_accessor_class = ReverseOneToOneDescriptor
rel_class = OneToOneRel
description = _("One-to-one relationship")
@@ -1560,7 +1560,7 @@ class ManyToManyField(RelatedField):
self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
# Add the descriptor for the m2m relation.
- setattr(cls, self.name, ManyRelatedObjectsDescriptor(self.remote_field, reverse=False))
+ setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False))
# Set up the accessor for the m2m table name for the relation.
self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
@@ -1569,7 +1569,7 @@ class ManyToManyField(RelatedField):
# Internal M2Ms (i.e., those with a related name ending with '+')
# and swapped models don't get a related descriptor.
if not self.remote_field.is_hidden() and not related.related_model._meta.swapped:
- setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(self.remote_field, reverse=True))
+ setattr(cls, related.get_accessor_name(), ManyToManyDescriptor(self.remote_field, reverse=True))
# Set up the accessors for the column names on the m2m table.
self.m2m_column_name = curry(self._get_m2m_attr, related, 'column')
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index 926704ad7d..2398b166bb 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -22,37 +22,42 @@ reverse many-to-one relation.
There are three types of relations (many-to-one, one-to-one, and many-to-many)
and two directions (forward and reverse) for a total of six combinations.
-However only four accessor classes are required.
1. Related instance on the forward side of a many-to-one or one-to-one
- relation: ``ReverseSingleRelatedObjectDescriptor``.
+ relation: ``ForwardManyToOneDescriptor``.
Uniqueness of foreign key values is irrelevant to accessing the related
instance, making the many-to-one and one-to-one cases identical as far as
the descriptor is concerned. The constraint is checked upstream (unicity
validation in forms) or downstream (unique indexes in the database).
+ If you're looking for ``ForwardOneToOneDescriptor``, use
+ ``ForwardManyToOneDescriptor`` instead.
+
2. Related instance on the reverse side of a one-to-one relation:
- ``SingleRelatedObjectDescriptor``.
+ ``ReverseOneToOneDescriptor``.
One-to-one relations are asymmetrical, despite the apparent symmetry of the
name, because they're implemented in the database with a foreign key from
- one table to another. As a consequence ``SingleRelatedObjectDescriptor`` is
- slightly different from ``ReverseSingleRelatedObjectDescriptor``.
+ one table to another. As a consequence ``ReverseOneToOneDescriptor`` is
+ slightly different from ``ForwardManyToOneDescriptor``.
3. Related objects manager for related instances on the reverse side of a
- many-to-one relation: ``ForeignRelatedObjectsDescriptor``.
+ many-to-one relation: ``ReverseManyToOneDescriptor``.
Unlike the previous two classes, this one provides access to a collection
of objects. It returns a manager rather than an instance.
4. Related objects manager for related instances on the forward or reverse
- sides of a many-to-many relation: ``ManyRelatedObjectsDescriptor``.
+ sides of a many-to-many relation: ``ManyToManyDescriptor``.
Many-to-many relations are symmetrical. The syntax of Django models
requires declaring them on one side but that's an implementation detail.
They could be declared on the other side without any change in behavior.
Therefore the forward and reverse descriptors can be the same.
+
+ If you're looking for ``ForwardManyToManyDescriptor`` or
+ ``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead.
"""
from __future__ import unicode_literals
@@ -65,7 +70,7 @@ from django.db.models.query import QuerySet
from django.utils.functional import cached_property
-class ReverseSingleRelatedObjectDescriptor(object):
+class ForwardManyToOneDescriptor(object):
"""
Accessor to the related object on the forward side of a many-to-one or
one-to-one relation.
@@ -75,7 +80,7 @@ class ReverseSingleRelatedObjectDescriptor(object):
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
- ``child.parent`` is a ``ReverseSingleRelatedObjectDescriptor`` instance.
+ ``child.parent`` is a ``ForwardManyToOneDescriptor`` instance.
"""
def __init__(self, field_with_rel):
@@ -150,7 +155,7 @@ class ReverseSingleRelatedObjectDescriptor(object):
# The related instance is loaded from the database and then cached in
# the attribute defined in self.cache_name. It can also be pre-cached
- # by the reverse accessor (SingleRelatedObjectDescriptor).
+ # by the reverse accessor (ReverseOneToOneDescriptor).
try:
rel_obj = getattr(instance, self.cache_name)
except AttributeError:
@@ -249,7 +254,7 @@ class ReverseSingleRelatedObjectDescriptor(object):
setattr(value, self.field.remote_field.get_cache_name(), instance)
-class SingleRelatedObjectDescriptor(object):
+class ReverseOneToOneDescriptor(object):
"""
Accessor to the related object on the reverse side of a one-to-one
relation.
@@ -259,7 +264,7 @@ class SingleRelatedObjectDescriptor(object):
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
- ``place.restaurant`` is a ``SingleRelatedObjectDescriptor`` instance.
+ ``place.restaurant`` is a ``ReverseOneToOneDescriptor`` instance.
"""
def __init__(self, related):
@@ -269,7 +274,7 @@ class SingleRelatedObjectDescriptor(object):
@cached_property
def RelatedObjectDoesNotExist(self):
# The exception isn't created at initialization time for the sake of
- # consistency with `ReverseSingleRelatedObjectDescriptor`.
+ # consistency with `ForwardManyToOneDescriptor`.
return type(
str('RelatedObjectDoesNotExist'),
(self.related.related_model.DoesNotExist, AttributeError),
@@ -323,7 +328,7 @@ class SingleRelatedObjectDescriptor(object):
# The related instance is loaded from the database and then cached in
# the attribute defined in self.cache_name. It can also be pre-cached
- # by the forward accessor (ReverseSingleRelatedObjectDescriptor).
+ # by the forward accessor (ForwardManyToOneDescriptor).
try:
rel_obj = getattr(instance, self.cache_name)
except AttributeError:
@@ -366,7 +371,7 @@ class SingleRelatedObjectDescriptor(object):
Keep in mind that ``Restaurant`` holds the foreign key to ``Place``.
"""
# The similarity of the code below to the code in
- # ReverseSingleRelatedObjectDescriptor is annoying, but there's a bunch
+ # ForwardManyToOneDescriptor is annoying, but there's a bunch
# of small differences that would make a common base class convoluted.
# If null=True, we can assign null here, but otherwise the value needs
@@ -410,7 +415,7 @@ class SingleRelatedObjectDescriptor(object):
setattr(value, self.related.field.get_cache_name(), instance)
-class ForeignRelatedObjectsDescriptor(object):
+class ReverseManyToOneDescriptor(object):
"""
Accessor to the related objects manager on the reverse side of a
many-to-one relation.
@@ -420,10 +425,10 @@ class ForeignRelatedObjectsDescriptor(object):
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
- ``parent.children`` is a ``ForeignRelatedObjectsDescriptor`` instance.
+ ``parent.children`` is a ``ReverseManyToOneDescriptor`` instance.
Most of the implementation is delegated to a dynamically defined manager
- class built by ``create_many_related_manager()`` which is defined below.
+ class built by ``create_forward_many_to_many_manager()`` defined below.
"""
def __init__(self, rel):
@@ -432,7 +437,7 @@ class ForeignRelatedObjectsDescriptor(object):
@cached_property
def related_manager_cls(self):
- return create_foreign_related_manager(
+ return create_reverse_many_to_one_manager(
self.rel.related_model._default_manager.__class__,
self.rel,
)
@@ -466,7 +471,7 @@ class ForeignRelatedObjectsDescriptor(object):
manager.set(value)
-def create_foreign_related_manager(superclass, rel):
+def create_reverse_many_to_one_manager(superclass, rel):
"""
Create a manager for the reverse side of a many-to-one relation.
@@ -488,7 +493,7 @@ def create_foreign_related_manager(superclass, rel):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
- manager_class = create_foreign_related_manager(manager.__class__, rel)
+ manager_class = create_reverse_many_to_one_manager(manager.__class__, rel)
return manager_class(self.instance)
do_not_call_in_templates = True
@@ -650,7 +655,7 @@ def create_foreign_related_manager(superclass, rel):
return RelatedManager
-class ManyRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
+class ManyToManyDescriptor(ReverseManyToOneDescriptor):
"""
Accessor to the related objects manager on the forward and reverse sides of
a many-to-many relation.
@@ -660,15 +665,15 @@ class ManyRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
class Pizza(Model):
toppings = ManyToManyField(Topping, related_name='pizzas')
- ``pizza.toppings`` and ``topping.pizzas`` are
- ``ManyRelatedObjectsDescriptor`` instances.
+ ``pizza.toppings`` and ``topping.pizzas`` are ``ManyToManyDescriptor``
+ instances.
Most of the implementation is delegated to a dynamically defined manager
- class built by ``create_many_related_manager()`` which is defined below.
+ class built by ``create_forward_many_to_many_manager()`` defined below.
"""
def __init__(self, rel, reverse=False):
- super(ManyRelatedObjectsDescriptor, self).__init__(rel)
+ super(ManyToManyDescriptor, self).__init__(rel)
self.reverse = reverse
@@ -682,14 +687,14 @@ class ManyRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
@cached_property
def related_manager_cls(self):
model = self.rel.related_model if self.reverse else self.rel.model
- return create_many_related_manager(
+ return create_forward_many_to_many_manager(
model._default_manager.__class__,
self.rel,
reverse=self.reverse,
)
-def create_many_related_manager(superclass, rel, reverse):
+def create_forward_many_to_many_manager(superclass, rel, reverse):
"""
Create a manager for the either side of a many-to-many relation.
@@ -746,7 +751,7 @@ def create_many_related_manager(superclass, rel, reverse):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
- manager_class = create_many_related_manager(manager.__class__, rel, reverse)
+ manager_class = create_forward_many_to_many_manager(manager.__class__, rel, reverse)
return manager_class(instance=self.instance)
do_not_call_in_templates = True
diff --git a/tests/foreign_object/models/article.py b/tests/foreign_object/models/article.py
index f9e6f1fca4..f0c2f3fbac 100644
--- a/tests/foreign_object/models/article.py
+++ b/tests/foreign_object/models/article.py
@@ -1,11 +1,10 @@
from django.db import models
-from django.db.models.fields.related import \
- ReverseSingleRelatedObjectDescriptor
+from django.db.models.fields.related import ForwardManyToOneDescriptor
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import get_language
-class ArticleTranslationDescriptor(ReverseSingleRelatedObjectDescriptor):
+class ArticleTranslationDescriptor(ForwardManyToOneDescriptor):
"""
The set of articletranslation should not set any local fields.
"""
diff --git a/tests/foreign_object/models/empty_join.py b/tests/foreign_object/models/empty_join.py
index 3bf121bf39..b8b05ea1c2 100644
--- a/tests/foreign_object/models/empty_join.py
+++ b/tests/foreign_object/models/empty_join.py
@@ -1,6 +1,6 @@
from django.db import models
from django.db.models.fields.related import (
- ForeignObjectRel, ForeignRelatedObjectsDescriptor,
+ ForeignObjectRel, ReverseManyToOneDescriptor,
)
from django.db.models.lookups import StartsWith
from django.db.models.query_utils import PathInfo
@@ -10,7 +10,7 @@ from django.utils.encoding import python_2_unicode_compatible
class CustomForeignObjectRel(ForeignObjectRel):
"""
Define some extra Field methods so this Rel acts more like a Field, which
- lets us use ForeignRelatedObjectsDescriptor in both directions.
+ lets us use ReverseManyToOneDescriptor in both directions.
"""
@property
def foreign_related_fields(self):
@@ -24,7 +24,7 @@ class StartsWithRelation(models.ForeignObject):
"""
A ForeignObject that uses StartsWith operator in its joins instead of
the default equality operator. This is logically a many-to-many relation
- and creates a ForeignRelatedObjectsDescriptor in both directions.
+ and creates a ReverseManyToOneDescriptor in both directions.
"""
auto_created = False
@@ -42,7 +42,7 @@ class StartsWithRelation(models.ForeignObject):
@property
def field(self):
"""
- Makes ForeignRelatedObjectsDescriptor work in both directions.
+ Makes ReverseManyToOneDescriptor work in both directions.
"""
return self.remote_field
@@ -66,7 +66,7 @@ class StartsWithRelation(models.ForeignObject):
def contribute_to_class(self, cls, name, virtual_only=False):
super(StartsWithRelation, self).contribute_to_class(cls, name, virtual_only)
- setattr(cls, self.name, ForeignRelatedObjectsDescriptor(self))
+ setattr(cls, self.name, ReverseManyToOneDescriptor(self))
class BrokenContainsRelation(StartsWithRelation):
diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py
index e9bd748329..72d4d492c6 100644
--- a/tests/generic_relations/tests.py
+++ b/tests/generic_relations/tests.py
@@ -329,7 +329,7 @@ class GenericRelationsTests(TestCase):
def test_assign_with_queryset(self):
# Ensure that querysets used in reverse GFK assignments are pre-evaluated
# so their value isn't affected by the clearing operation in
- # ManyRelatedObjectsDescriptor.__set__. Refs #19816.
+ # ManyToManyDescriptor.__set__. Refs #19816.
bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
bacon.tags.create(tag="fatty")
bacon.tags.create(tag="salty")
diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py
index ffe5e879ca..be18dcedb0 100644
--- a/tests/many_to_many/tests.py
+++ b/tests/many_to_many/tests.py
@@ -412,7 +412,7 @@ class ManyToManyTests(TestCase):
def test_forward_assign_with_queryset(self):
# Ensure that querysets used in m2m assignments are pre-evaluated
# so their value isn't affected by the clearing operation in
- # ManyRelatedObjectsDescriptor.__set__. Refs #19816.
+ # ManyToManyDescriptor.__set__. Refs #19816.
self.a1.publications = [self.p1, self.p2]
qs = self.a1.publications.filter(title='The Python Journal')
@@ -424,7 +424,7 @@ class ManyToManyTests(TestCase):
def test_reverse_assign_with_queryset(self):
# Ensure that querysets used in M2M assignments are pre-evaluated
# so their value isn't affected by the clearing operation in
- # ManyRelatedObjectsDescriptor.__set__. Refs #19816.
+ # ManyToManyDescriptor.__set__. Refs #19816.
self.p1.article_set = [self.a1, self.a2]
qs = self.p1.article_set.filter(headline='Django lets you build Web apps easily')
diff --git a/tests/many_to_one_null/tests.py b/tests/many_to_one_null/tests.py
index 06f756e35b..ae5e21e1cf 100644
--- a/tests/many_to_one_null/tests.py
+++ b/tests/many_to_one_null/tests.py
@@ -106,7 +106,7 @@ class ManyToOneNullTests(TestCase):
def test_assign_with_queryset(self):
# Ensure that querysets used in reverse FK assignments are pre-evaluated
# so their value isn't affected by the clearing operation in
- # ForeignRelatedObjectsDescriptor.__set__. Refs #19816.
+ # ReverseManyToOneDescriptor.__set__. Refs #19816.
self.r2.article_set = [self.a2, self.a3]
qs = self.r2.article_set.filter(headline="Second")
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index 0a864e93ae..7aed238bc0 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -595,7 +595,7 @@ class CustomPrefetchTests(TestCase):
self.assertEqual(lst2[0].houses_lst[0].rooms_lst[0].main_room_of, self.house1)
self.assertEqual(len(lst2[1].houses_lst), 0)
- # Test ReverseSingleRelatedObjectDescriptor.
+ # Test ForwardManyToOneDescriptor.
houses = House.objects.select_related('owner')
with self.assertNumQueries(6):
rooms = Room.objects.all().prefetch_related('house')
@@ -624,7 +624,7 @@ class CustomPrefetchTests(TestCase):
with self.assertNumQueries(3):
getattr(rooms.first().house, 'address')
- # Test SingleRelatedObjectDescriptor.
+ # Test ReverseOneToOneDescriptor.
houses = House.objects.select_related('owner')
with self.assertNumQueries(6):
rooms = Room.objects.all().prefetch_related('main_room_of')
diff --git a/tests/schema/fields.py b/tests/schema/fields.py
index 8499477d65..30357b1061 100644
--- a/tests/schema/fields.py
+++ b/tests/schema/fields.py
@@ -1,6 +1,6 @@
from django.db import models
from django.db.models.fields.related import (
- RECURSIVE_RELATIONSHIP_CONSTANT, ManyRelatedObjectsDescriptor,
+ RECURSIVE_RELATIONSHIP_CONSTANT, ManyToManyDescriptor,
ManyToManyField, ManyToManyRel, RelatedField,
create_many_to_many_intermediary_model,
)
@@ -42,7 +42,7 @@ class CustomManyToManyField(RelatedField):
super(CustomManyToManyField, self).contribute_to_class(cls, name, **kwargs)
if not self.remote_field.through and not cls._meta.abstract and not cls._meta.swapped:
self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
- setattr(cls, self.name, ManyRelatedObjectsDescriptor(self.remote_field))
+ setattr(cls, self.name, ManyToManyDescriptor(self.remote_field))
self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
def get_internal_type(self):