diff --git a/django/db/models/options.py b/django/db/models/options.py index 670e2a5a2f..38f2fcfefc 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -369,11 +369,16 @@ class Options(object): @cached_property def managers(self): managers = [] + seen_managers = set() bases = (b for b in self.model.mro() if hasattr(b, '_meta')) for depth, base in enumerate(bases): for manager in base._meta.local_managers: + if manager.name in seen_managers: + continue + manager = copy.copy(manager) manager.model = self.model + seen_managers.add(manager.name) managers.append((depth, manager.creation_counter, manager)) # Used for deprecation of legacy manager inheritance, @@ -387,7 +392,7 @@ class Options(object): @cached_property def managers_map(self): - return {manager.name: manager for manager in reversed(self.managers)} + return {manager.name: manager for manager in self.managers} @cached_property def base_manager(self): diff --git a/docs/releases/1.10.1.txt b/docs/releases/1.10.1.txt index a13ecbb10a..0094f8137e 100644 --- a/docs/releases/1.10.1.txt +++ b/docs/releases/1.10.1.txt @@ -56,3 +56,5 @@ Bugfixes * Reallowed the ``{% for %}`` tag to unpack any iterable (:ticket:`27058`). * Fixed ``makemigrations`` crash if a database is read-only (:ticket:`27054`). + +* Removed duplicated managers in ``Model._meta.managers`` (:ticket:`27073`). diff --git a/tests/managers_regress/tests.py b/tests/managers_regress/tests.py index feaca1cba0..1ff34dede3 100644 --- a/tests/managers_regress/tests.py +++ b/tests/managers_regress/tests.py @@ -286,6 +286,22 @@ class TestManagerInheritance(TestCase): self.assertIsInstance(MTIModel._base_manager, CustomManager) + def test_manager_no_duplicates(self): + class CustomManager(models.Manager): + pass + + class AbstractModel(models.Model): + custom_manager = models.Manager() + + class Meta: + abstract = True + + class TestModel(AbstractModel): + custom_manager = CustomManager() + + self.assertEqual(TestModel._meta.managers, (TestModel.custom_manager,)) + self.assertEqual(TestModel._meta.managers_map, {'custom_manager': TestModel.custom_manager}) + @isolate_apps('managers_regress') class TestManagerDeprecations(TestCase):