summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAlex Hill <alex@hill.net.au>2015-03-03 16:43:56 +0800
committerTim Graham <timograham@gmail.com>2015-03-25 16:48:17 -0400
commit720ff740e70e649a97fcf0232fec132569a52c7e (patch)
tree688533ec18f1d970b8c7671ef94be83b67720b80 /tests
parent0f6f80c2e7736ec4e2aa40287fe8c37ffff0a783 (diff)
Fixed #24215 -- Refactored lazy model operations
This adds a new method, Apps.lazy_model_operation(), and a helper function, lazy_related_operation(), which together supersede add_lazy_relation() and make lazy model operations the responsibility of the App registry. This system no longer uses the class_prepared signal.
Diffstat (limited to 'tests')
-rw-r--r--tests/apps/tests.py38
-rw-r--r--tests/model_fields/models.py11
-rw-r--r--tests/model_fields/tests.py59
3 files changed, 72 insertions, 36 deletions
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index 89e295ffde..347996454f 100644
--- a/tests/apps/tests.py
+++ b/tests/apps/tests.py
@@ -259,6 +259,44 @@ class AppsTests(TestCase):
finally:
apps.apps_ready = True
+ def test_lazy_model_operation(self):
+ """
+ Tests apps.lazy_model_operation().
+ """
+ model_classes = []
+ initial_pending = set(apps._pending_operations)
+
+ def test_func(*models):
+ model_classes[:] = models
+
+ class LazyA(models.Model):
+ pass
+
+ # Test models appearing twice, and models appearing consecutively
+ model_keys = [('apps', model_name) for model_name in ['lazya', 'lazyb', 'lazyb', 'lazyc', 'lazya']]
+ apps.lazy_model_operation(test_func, *model_keys)
+
+ # LazyModelA shouldn't be waited on since it's already registered,
+ # and LazyModelC shouldn't be waited on until LazyModelB exists.
+ self.assertSetEqual(set(apps._pending_operations) - initial_pending, {('apps', 'lazyb')})
+
+ # Test that multiple operations can wait on the same model
+ apps.lazy_model_operation(test_func, ('apps', 'lazyb'))
+
+ class LazyB(models.Model):
+ pass
+
+ self.assertListEqual(model_classes, [LazyB])
+
+ # Now we are just waiting on LazyModelC.
+ self.assertSetEqual(set(apps._pending_operations) - initial_pending, {('apps', 'lazyc')})
+
+ class LazyC(models.Model):
+ pass
+
+ # Everything should be loaded - make sure the callback was executed properly.
+ self.assertListEqual(model_classes, [LazyA, LazyB, LazyB, LazyC, LazyA])
+
class Stub(object):
def __init__(self, **kwargs):
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
index 4208454b68..cca2b463a0 100644
--- a/tests/model_fields/models.py
+++ b/tests/model_fields/models.py
@@ -373,14 +373,3 @@ class PrimaryKeyUUIDModel(models.Model):
class RelatedToUUIDModel(models.Model):
uuid_fk = models.ForeignKey('PrimaryKeyUUIDModel')
-
-
-###############################################################################
-
-# See ticket #24215.
-class AbstractForeignFieldsModel(models.Model):
- fk = models.ForeignKey('missing.FK')
- m2m = models.ManyToManyField('missing.M2M', through='missing.Through')
-
- class Meta:
- abstract = True
diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py
index 31f2cee337..6b63b8f115 100644
--- a/tests/model_fields/tests.py
+++ b/tests/model_fields/tests.py
@@ -5,6 +5,7 @@ import unittest
from decimal import Decimal
from django import forms, test
+from django.apps import apps
from django.core import checks, validators
from django.core.exceptions import ValidationError
from django.db import IntegrityError, connection, models, transaction
@@ -21,12 +22,11 @@ from django.utils import six
from django.utils.functional import lazy
from .models import (
- 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,
+ 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,
)
@@ -202,37 +202,46 @@ class ForeignKeyTests(test.TestCase):
rel_name = Bar._meta.get_field('a').remote_field.related_name
self.assertIsInstance(rel_name, six.text_type)
- def test_abstract_model_pending_lookups(self):
+ def test_abstract_model_pending_operations(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'
+ pending_ops_before = list(apps._pending_operations.items())
+
+ class AbstractForeignKeyModel(models.Model):
+ fk = models.ForeignKey('missing.FK')
+
+ class Meta:
+ abstract = True
+
+ self.assertIs(AbstractForeignKeyModel._meta.apps, apps)
+ self.assertEqual(
+ pending_ops_before,
+ list(apps._pending_operations.items()),
+ "Pending lookup added for a foreign key on an abstract model"
)
class ManyToManyFieldTests(test.TestCase):
- def test_abstract_model_pending_lookups(self):
+ def test_abstract_model_pending_operations(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.'
+ pending_ops_before = list(apps._pending_operations.items())
+
+ class AbstractManyToManyModel(models.Model):
+ fk = models.ForeignKey('missing.FK')
+
+ class Meta:
+ abstract = True
+
+ self.assertIs(AbstractManyToManyModel._meta.apps, apps)
+ self.assertEqual(
+ pending_ops_before,
+ list(apps._pending_operations.items()),
+ "Pending lookup added for a many-to-many field on an abstract model"
)