mirror of https://github.com/django/django.git
Refs #24215 -- Prevented pending lookup pollution by abstract models.
This commit is contained in:
parent
e519ee1d35
commit
9239f1dda7
|
@ -291,20 +291,21 @@ class RelatedField(Field):
|
||||||
if hasattr(sup, 'contribute_to_class'):
|
if hasattr(sup, 'contribute_to_class'):
|
||||||
sup.contribute_to_class(cls, name, virtual_only=virtual_only)
|
sup.contribute_to_class(cls, name, virtual_only=virtual_only)
|
||||||
|
|
||||||
if not cls._meta.abstract and self.rel.related_name:
|
if not cls._meta.abstract:
|
||||||
related_name = force_text(self.rel.related_name) % {
|
if self.rel.related_name:
|
||||||
'class': cls.__name__.lower(),
|
related_name = force_text(self.rel.related_name) % {
|
||||||
'app_label': cls._meta.app_label.lower()
|
'class': cls.__name__.lower(),
|
||||||
}
|
'app_label': cls._meta.app_label.lower()
|
||||||
self.rel.related_name = related_name
|
}
|
||||||
other = self.rel.to
|
self.rel.related_name = related_name
|
||||||
if isinstance(other, six.string_types) or other._meta.pk is None:
|
other = self.rel.to
|
||||||
def resolve_related_class(field, model, cls):
|
if isinstance(other, six.string_types) or other._meta.pk is None:
|
||||||
field.rel.to = model
|
def resolve_related_class(field, model, cls):
|
||||||
field.do_related_class(model, cls)
|
field.rel.to = model
|
||||||
add_lazy_relation(cls, self, other, resolve_related_class)
|
field.do_related_class(model, cls)
|
||||||
else:
|
add_lazy_relation(cls, self, other, resolve_related_class)
|
||||||
self.do_related_class(other, cls)
|
else:
|
||||||
|
self.do_related_class(other, cls)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swappable_setting(self):
|
def swappable_setting(self):
|
||||||
|
@ -2605,7 +2606,7 @@ class ManyToManyField(RelatedField):
|
||||||
|
|
||||||
# Populate some necessary rel arguments so that cross-app relations
|
# Populate some necessary rel arguments so that cross-app relations
|
||||||
# work correctly.
|
# work correctly.
|
||||||
if isinstance(self.rel.through, six.string_types):
|
if not cls._meta.abstract and isinstance(self.rel.through, six.string_types):
|
||||||
def resolve_through_model(field, model, cls):
|
def resolve_through_model(field, model, cls):
|
||||||
field.rel.through = model
|
field.rel.through = model
|
||||||
add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
|
add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
|
||||||
|
|
|
@ -367,3 +367,14 @@ class NullableUUIDModel(models.Model):
|
||||||
|
|
||||||
class PrimaryKeyUUIDModel(models.Model):
|
class PrimaryKeyUUIDModel(models.Model):
|
||||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# See ticket #24215.
|
||||||
|
class AbstractForeignFieldsModel(models.Model):
|
||||||
|
fk = models.ForeignKey('missing.FK')
|
||||||
|
m2m = models.ManyToManyField('missing.M2M', through='missing.Through')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
|
@ -21,11 +21,12 @@ from django.utils import six
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Bar, BigD, BigIntegerModel, BigS, BooleanModel, DataModel, DateTimeModel,
|
AbstractForeignFieldsModel, Bar, BigD, BigIntegerModel, BigS, BooleanModel,
|
||||||
Document, FksToBooleans, FkToChar, FloatModel, Foo, GenericIPAddress,
|
DataModel, DateTimeModel, Document, FksToBooleans, FkToChar, FloatModel,
|
||||||
IntegerModel, NullBooleanModel, PositiveIntegerModel,
|
Foo, GenericIPAddress, IntegerModel, NullBooleanModel,
|
||||||
PositiveSmallIntegerModel, Post, PrimaryKeyCharModel, RenamedField,
|
PositiveIntegerModel, PositiveSmallIntegerModel, Post, PrimaryKeyCharModel,
|
||||||
SmallIntegerModel, VerboseNameField, Whiz, WhizIter, WhizIterEmpty,
|
RenamedField, SmallIntegerModel, VerboseNameField, Whiz, WhizIter,
|
||||||
|
WhizIterEmpty,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,6 +202,39 @@ class ForeignKeyTests(test.TestCase):
|
||||||
rel_name = Bar._meta.get_field('a').rel.related_name
|
rel_name = Bar._meta.get_field('a').rel.related_name
|
||||||
self.assertIsInstance(rel_name, six.text_type)
|
self.assertIsInstance(rel_name, six.text_type)
|
||||||
|
|
||||||
|
def test_abstract_model_pending_lookups(self):
|
||||||
|
"""
|
||||||
|
Foreign key fields declared on abstract models should not add lazy relations to
|
||||||
|
resolve relationship declared as string. refs #24215
|
||||||
|
"""
|
||||||
|
opts = AbstractForeignFieldsModel._meta
|
||||||
|
to_key = ('missing', 'FK')
|
||||||
|
fk_lookup = (AbstractForeignFieldsModel, opts.get_field('fk'))
|
||||||
|
self.assertFalse(
|
||||||
|
any(lookup[0:2] == fk_lookup for lookup in opts.apps._pending_lookups.get(to_key, [])),
|
||||||
|
'Pending lookup added for the abstract model foreign key `to` parameter'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ManyToManyFieldTests(test.TestCase):
|
||||||
|
def test_abstract_model_pending_lookups(self):
|
||||||
|
"""
|
||||||
|
Many-to-many fields declared on abstract models should not add lazy relations to
|
||||||
|
resolve relationship declared as string. refs #24215
|
||||||
|
"""
|
||||||
|
opts = AbstractForeignFieldsModel._meta
|
||||||
|
to_key = ('missing', 'M2M')
|
||||||
|
fk_lookup = (AbstractForeignFieldsModel, opts.get_field('m2m'))
|
||||||
|
self.assertFalse(
|
||||||
|
any(lookup[0:2] == fk_lookup for lookup in opts.apps._pending_lookups.get(to_key, [])),
|
||||||
|
'Pending lookup added for the abstract model many-to-many `to` parameter.'
|
||||||
|
)
|
||||||
|
through_key = ('missing', 'Through')
|
||||||
|
self.assertFalse(
|
||||||
|
any(lookup[0:2] == fk_lookup for lookup in opts.apps._pending_lookups.get(through_key, [])),
|
||||||
|
'Pending lookup added for the abstract model many-to-many `through` parameter.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DateTimeFieldTests(unittest.TestCase):
|
class DateTimeFieldTests(unittest.TestCase):
|
||||||
def test_datetimefield_to_python_usecs(self):
|
def test_datetimefield_to_python_usecs(self):
|
||||||
|
|
Loading…
Reference in New Issue