Commit 9239f1dd authored by Simon Charette's avatar Simon Charette
Browse files

Refs #24215 -- Prevented pending lookup pollution by abstract models.

parent e519ee1d
Loading
Loading
Loading
Loading
+16 −15
Original line number Diff line number Diff line
@@ -291,7 +291,8 @@ class RelatedField(Field):
        if hasattr(sup, 'contribute_to_class'):
            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:
            if self.rel.related_name:
                related_name = force_text(self.rel.related_name) % {
                    'class': cls.__name__.lower(),
                    'app_label': cls._meta.app_label.lower()
@@ -2605,7 +2606,7 @@ class ManyToManyField(RelatedField):

        # Populate some necessary rel arguments so that cross-app relations
        # 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):
                field.rel.through = model
            add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
+11 −0
Original line number Diff line number Diff line
@@ -367,3 +367,14 @@ class NullableUUIDModel(models.Model):

class PrimaryKeyUUIDModel(models.Model):
    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
+39 −5
Original line number Diff line number Diff line
@@ -21,11 +21,12 @@ from django.utils import six
from django.utils.functional import lazy

from .models import (
    Bar, BigD, BigIntegerModel, BigS, BooleanModel, DataModel, DateTimeModel,
    Document, FksToBooleans, FkToChar, FloatModel, Foo, GenericIPAddress,
    IntegerModel, NullBooleanModel, PositiveIntegerModel,
    PositiveSmallIntegerModel, Post, PrimaryKeyCharModel, RenamedField,
    SmallIntegerModel, VerboseNameField, Whiz, WhizIter, WhizIterEmpty,
    AbstractForeignFieldsModel, Bar, BigD, BigIntegerModel, BigS, BooleanModel,
    DataModel, DateTimeModel, Document, FksToBooleans, FkToChar, FloatModel,
    Foo, GenericIPAddress, IntegerModel, NullBooleanModel,
    PositiveIntegerModel, PositiveSmallIntegerModel, Post, PrimaryKeyCharModel,
    RenamedField, SmallIntegerModel, VerboseNameField, Whiz, WhizIter,
    WhizIterEmpty,
)


@@ -201,6 +202,39 @@ class ForeignKeyTests(test.TestCase):
        rel_name = Bar._meta.get_field('a').rel.related_name
        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):
    def test_datetimefield_to_python_usecs(self):