diff options
| author | Alex Hill <alex@hill.net.au> | 2015-03-03 16:43:56 +0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-03-25 16:48:17 -0400 |
| commit | 720ff740e70e649a97fcf0232fec132569a52c7e (patch) | |
| tree | 688533ec18f1d970b8c7671ef94be83b67720b80 /tests | |
| parent | 0f6f80c2e7736ec4e2aa40287fe8c37ffff0a783 (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.py | 38 | ||||
| -rw-r--r-- | tests/model_fields/models.py | 11 | ||||
| -rw-r--r-- | tests/model_fields/tests.py | 59 |
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" ) |
