Add proper support for pre/post migrate/sync signals.

Review Request #10582 — Created June 7, 2019 and submitted

Information

Django Evolution
master

Reviewers

We were trying to emit pre_migrate/post_migrate signals in
apply_migrations(), which was always intended to be temporary. While
emitting them there sort of worked at one point (when there was only one
migration phase), it falls apart pretty hard with some apps with
multiple migration phases. The reason is that some apps will use the
post_migrate signal to inject some state into the database for the new
models, but this happens too soon when emitted during the initial
migration phase.

We also weren't emitting the pre_sync and post_sync signals on
Django 1.6 and earlier (1.7 and 1.8 would emit them for
backwards-compatibility, though).

To solve all this, this change does four things:

  1. It switches to emitting the pre_migrate signal only once, before
    any migrations are applied, and post_migrate only once, after all
    migrations are applied.

  2. It introduces a full migration plan that encompasses all phases of
    the migrations, which allows us to provide some useful state in these
    signals. This is important as some apps listen to pre_migrate and
    then modify the migration instances that are to be later applied.

  3. It also splits apply_migrations() into three functions:
    create_pre_migrate_state(), apply_migrations(), and
    finalize_migrations(). This allows repeated alterations of the same
    migration state, and a single final model rendering phase, better
    mirroring what's done directly in Django's migrate command.

  4. It emits pre_sync and post_sync signals on Django 1.6 and
    earlier.

Unit tests pass on all supported versions of Django.

Manually tested population of a new database and upgrades of an
existing one (utilizing both migrations and evolutions).

Summary ID
Add proper support for pre/post migrate/sync signals.
We were trying to emit `pre_migrate`/`post_migrate` signals in `apply_migrations()`, which was always intended to be temporary. While emitting them there sort of worked at one point (when there was only one migration phase), it falls apart pretty hard with some apps with multiple migration phases. The reason is that some apps will use the `post_migrate` signal to inject some state into the database for the new models, but this happens too soon when emitted during the initial migration phase. We also weren't emitting the `pre_sync` and `post_sync` signals on Django 1.6 and earlier (1.7 and 1.8 would emit them for backwards-compatibility, though). To solve all this, this change does four things: 1. It switches to emitting the `pre_migrate` signal only once, before any migrations are applied, and `post_migrate` only once, after all migrations are applied. 2. It introduces a full migration plan that encompasses all phases of the migrations, which allows us to provide some useful state in these signals. This is important as some apps listen to `pre_migrate` and then modify the migration instances that are to be later applied. 3. It also splits `apply_migrations()` into three functions: `create_pre_migrate_state()`, `apply_migrations()`, and `finalize_migrations()`. This allows repeated alterations of the same migration state, and a single final model rendering phase, better mirroring what's done directly in Django's `migrate` command. 4. It emits `pre_sync` and `post_sync` signals on Django 1.6 and earlier.
04e561d54c8686fe89a8c40c8e6b28195f06fea0
chipx86
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to master (e86342c)