Commit dab83e5b authored by Loïc Bistuer's avatar Loïc Bistuer
Browse files

Fixed #26881 -- Fixed duplicate managers in migrations.

When both parent and child models had managers with the same name and
a migrations opt-in both were added to the migration state.
parent ba53da89
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -447,12 +447,19 @@ class ModelState(object):
            bases = (models.Model,)

        managers = []
        manager_names = set()
        default_manager_shim = None
        for manager in model._meta.managers:
            if manager.use_in_migrations:
            manager_name = force_text(manager.name)
            if manager_name in manager_names:
                # Skip overridden managers.
                continue
            elif manager.use_in_migrations:
                # Copy managers usable in migrations.
                new_manager = copy.copy(manager)
                new_manager._set_creation_counter()
            elif manager is model._base_manager or manager is model._default_manager:
                # Shim custom managers used as default and base managers.
                new_manager = models.Manager()
                new_manager.model = manager.model
                new_manager.name = manager.name
@@ -460,7 +467,8 @@ class ModelState(object):
                    default_manager_shim = new_manager
            else:
                continue
            managers.append((force_text(manager.name), new_manager))
            manager_names.add(manager_name)
            managers.append((manager_name, new_manager))

        # Ignore a shimmed default manager called objects if it's the only one.
        if managers == [('objects', default_manager_shim)]:
+31 −0
Original line number Diff line number Diff line
@@ -210,6 +210,37 @@ class StateTests(SimpleTestCase):
        author_state = project_state.models['migrations', 'author']
        self.assertEqual(author_state.managers, [])

    def test_no_duplicate_managers(self):
        """
        When a manager is added with `use_in_migrations = True` and a parent
        model had a manager with the same name and `use_in_migrations = True`,
        the parent's manager shouldn't appear in the model state (#26881).
        """
        new_apps = Apps(['migrations'])

        class PersonManager(models.Manager):
            use_in_migrations = True

        class Person(models.Model):
            objects = PersonManager()

            class Meta:
                abstract = True

        class BossManager(PersonManager):
            use_in_migrations = True

        class Boss(Person):
            objects = BossManager()

            class Meta:
                app_label = 'migrations'
                apps = new_apps

        project_state = ProjectState.from_apps(new_apps)
        boss_state = project_state.models['migrations', 'boss']
        self.assertEqual(boss_state.managers, [('objects', Boss.objects)])

    def test_custom_default_manager(self):
        new_apps = Apps(['migrations'])