From 45edb9d2359c60952fd791616df887eb95f75746 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Tue, 18 Feb 2014 10:19:04 +0100 Subject: [PATCH] Fixed #22057 -- Ensured reverse_lazy can be used in settings And without causing a circular import. Thanks Akis Kesoglou for the report. --- django/db/models/sql/aggregates.py | 19 ++++++++++++------- tests/admin_scripts/tests.py | 4 +++- tests/urlpatterns_reverse/tests.py | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/django/db/models/sql/aggregates.py b/django/db/models/sql/aggregates.py index aef8b493bb..ce2968c445 100644 --- a/django/db/models/sql/aggregates.py +++ b/django/db/models/sql/aggregates.py @@ -5,16 +5,12 @@ import copy from django.db.models.fields import IntegerField, FloatField from django.db.models.lookups import RegisterLookupMixin +from django.utils.functional import cached_property __all__ = ['Aggregate', 'Avg', 'Count', 'Max', 'Min', 'StdDev', 'Sum', 'Variance'] -# Fake fields used to identify aggregate types in data-conversion operations. -ordinal_aggregate_field = IntegerField() -computed_aggregate_field = FloatField() - - class Aggregate(RegisterLookupMixin): """ Default SQL Aggregate. @@ -61,14 +57,23 @@ class Aggregate(RegisterLookupMixin): while tmp and isinstance(tmp, Aggregate): if getattr(tmp, 'is_ordinal', False): - tmp = ordinal_aggregate_field + tmp = self._ordinal_aggregate_field elif getattr(tmp, 'is_computed', False): - tmp = computed_aggregate_field + tmp = self._computed_aggregate_field else: tmp = tmp.source self.field = tmp + # Two fake fields used to identify aggregate types in data-conversion operations. + @cached_property + def _ordinal_aggregate_field(self): + return IntegerField() + + @cached_property + def _computed_aggregate_field(self): + return FloatField() + def relabeled_clone(self, change_map): clone = copy.copy(self) if isinstance(self.col, (list, tuple)): diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 19be4a3372..af6aa92754 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -40,7 +40,7 @@ custom_templates_dir = os.path.join(os.path.dirname(__file__), 'custom_templates class AdminScriptTestCase(unittest.TestCase): - def write_settings(self, filename, apps=None, is_dir=False, sdict=None): + def write_settings(self, filename, apps=None, is_dir=False, sdict=None, extra=None): if is_dir: settings_dir = os.path.join(test_dir, filename) os.mkdir(settings_dir) @@ -51,6 +51,8 @@ class AdminScriptTestCase(unittest.TestCase): with open(settings_file_path, 'w') as settings_file: settings_file.write('# -*- coding: utf-8 -*\n') settings_file.write('# Settings file automatically generated by admin_scripts test case\n') + if extra: + settings_file.write("%s\n" % extra) exports = [ 'DATABASES', 'ROOT_URLCONF', diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py index a7fb342da7..2724716783 100644 --- a/tests/urlpatterns_reverse/tests.py +++ b/tests/urlpatterns_reverse/tests.py @@ -15,6 +15,8 @@ from django.shortcuts import redirect from django.test import TestCase, override_settings from django.utils import six +from admin_scripts.tests import AdminScriptTestCase + from . import urlconf_outer, middleware, views from .views import empty_view @@ -301,6 +303,24 @@ class ReverseLazyTest(TestCase): self.assertEqual(response.status_code, 200) +class ReverseLazySettingsTest(AdminScriptTestCase): + """ + Test that reverse_lazy can be used in settings without causing a circular + import error. + """ + def setUp(self): + self.write_settings('settings.py', extra=""" +from django.core.urlresolvers import reverse_lazy +LOGIN_URL = reverse_lazy('login')""") + + def tearDown(self): + self.remove_settings('settings.py') + + def test_lazy_in_settings(self): + out, err = self.run_manage(['test']) + self.assertOutput(err, "Ran 0 tests") + + class ReverseShortcutTests(TestCase): urls = 'urlpatterns_reverse.urls'