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:
parent
2409a4241a
commit
e542e81b39
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue