Commit bbbed99f authored by Markus Holtermann's avatar Markus Holtermann
Browse files

Fixed #24123 -- Used all available migrations to generate the initial migration state

Thanks Collin Anderson for the input when creating the patch and Tim Graham for the review.
parent 8f5d6c77
Loading
Loading
Loading
Loading
+25 −7
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ from django.db import migrations
from django.apps.registry import apps as global_apps
from .loader import MigrationLoader
from .recorder import MigrationRecorder
from .state import ProjectState


class MigrationExecutor(object):
@@ -18,11 +19,14 @@ class MigrationExecutor(object):
        self.recorder = MigrationRecorder(self.connection)
        self.progress_callback = progress_callback

    def migration_plan(self, targets):
    def migration_plan(self, targets, clean_start=False):
        """
        Given a set of targets, returns a list of (Migration instance, backwards?).
        """
        plan = []
        if clean_start:
            applied = set()
        else:
            applied = set(self.loader.applied_migrations)
        for target in targets:
            # If the target is (app_label, None), that means unmigrate everything
@@ -60,17 +64,31 @@ class MigrationExecutor(object):
    def migrate(self, targets, plan=None, fake=False):
        """
        Migrates the database up to the given targets.

        Django first needs to create all project states before a migration is
        (un)applied and in a second step run all the database operations.
        """
        if plan is None:
            plan = self.migration_plan(targets)
        state = None
        migrations_to_run = {m[0] for m in plan}
        # Create the forwards plan Django would follow on an empty database
        full_plan = self.migration_plan(self.loader.graph.leaf_nodes(), clean_start=True)
        # Holds all states right before and right after a migration is applied
        # if the migration is being run.
        states = {}
        state = ProjectState(real_apps=list(self.loader.unmigrated_apps))
        state.apps  # Render all real_apps -- performance critical
        # Phase 1 -- Store all required states
        for migration, _ in full_plan:
            if migration in migrations_to_run:
                states[migration] = state.clone()
            state = migration.mutate_state(state)  # state is cloned inside
        # Phase 2 -- Run the migrations
        for migration, backwards in plan:
            if state is None:
                state = self.loader.project_state((migration.app_label, migration.name), at_end=False)
            if not backwards:
                state = self.apply_migration(state, migration, fake=fake)
                self.apply_migration(states[migration], migration, fake=fake)
            else:
                state = self.unapply_migration(state, migration, fake=fake)
                self.unapply_migration(states[migration], migration, fake=fake)

    def collect_sql(self, plan):
        """
+0 −0

Empty file added.

+19 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='A1',
            fields=[
                ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
            ],
        ),
    ]
+20 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
        ('lookuperror_a', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='A2',
            fields=[
                ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
            ],
        ),
    ]
+24 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
        ('lookuperror_c', '0002_c2'),
        ('lookuperror_b', '0002_b2'),
        ('lookuperror_a', '0002_a2'),
    ]

    operations = [
        migrations.CreateModel(
            name='A3',
            fields=[
                ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
                ('b2', models.ForeignKey(to='lookuperror_b.B2')),
                ('c2', models.ForeignKey(to='lookuperror_c.C2')),
            ],
        ),
    ]
Loading