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

This commit is contained in:
Loïc Bistuer 2016-08-19 01:24:45 +07:00 committed by GitHub
parent 8cd900c819
commit d4eefc7e2a
3 changed files with 24 additions and 1 deletions

View File

@ -369,11 +369,16 @@ class Options(object):
@cached_property @cached_property
def managers(self): def managers(self):
managers = [] managers = []
seen_managers = set()
bases = (b for b in self.model.mro() if hasattr(b, '_meta')) bases = (b for b in self.model.mro() if hasattr(b, '_meta'))
for depth, base in enumerate(bases): for depth, base in enumerate(bases):
for manager in base._meta.local_managers: for manager in base._meta.local_managers:
if manager.name in seen_managers:
continue
manager = copy.copy(manager) manager = copy.copy(manager)
manager.model = self.model manager.model = self.model
seen_managers.add(manager.name)
managers.append((depth, manager.creation_counter, manager)) managers.append((depth, manager.creation_counter, manager))
# Used for deprecation of legacy manager inheritance, # Used for deprecation of legacy manager inheritance,
@ -387,7 +392,7 @@ class Options(object):
@cached_property @cached_property
def managers_map(self): 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 @cached_property
def base_manager(self): def base_manager(self):

View File

@ -56,3 +56,5 @@ Bugfixes
* Reallowed the ``{% for %}`` tag to unpack any iterable (:ticket:`27058`). * Reallowed the ``{% for %}`` tag to unpack any iterable (:ticket:`27058`).
* Fixed ``makemigrations`` crash if a database is read-only (:ticket:`27054`). * Fixed ``makemigrations`` crash if a database is read-only (:ticket:`27054`).
* Removed duplicated managers in ``Model._meta.managers`` (:ticket:`27073`).

View File

@ -286,6 +286,22 @@ class TestManagerInheritance(TestCase):
self.assertIsInstance(MTIModel._base_manager, CustomManager) 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') @isolate_apps('managers_regress')
class TestManagerDeprecations(TestCase): class TestManagerDeprecations(TestCase):