mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
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.
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user