Browse Source

Fixed #27073 -- Removed duplicated managers in `Model._meta.managers`.

Loïc Bistuer 8 years ago
parent
commit
d4eefc7e2a
3 changed files with 24 additions and 1 deletions
  1. 6 1
      django/db/models/options.py
  2. 2 0
      docs/releases/1.10.1.txt
  3. 16 0
      tests/managers_regress/tests.py

+ 6 - 1
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):

+ 2 - 0
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`).

+ 16 - 0
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):