diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 8e1d2ace09..5465c24509 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -640,6 +640,9 @@ STATICFILES_FINDERS = [ # MIGRATIONS # ############## +# Executor to use for migration. +MIGRATION_EXECUTOR_BACKEND = 'django.db.migrations.executor.MigrationExecutor' + # Migration module overrides for apps, by app label. MIGRATION_MODULES = {} diff --git a/django/core/management/base.py b/django/core/management/base.py index 41b17a24c8..e67996caff 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -15,6 +15,7 @@ from django.core import checks from django.core.exceptions import ImproperlyConfigured from django.core.management.color import color_style, no_style from django.db import DEFAULT_DB_ALIAS, connections +from django.db.migrations.utils import get_migrate_executor ALL_CHECKS = "__all__" @@ -575,7 +576,7 @@ class BaseCommand: Print a warning if the set of migrations on disk don't match the migrations in the database. """ - from django.db.migrations.executor import MigrationExecutor + MigrationExecutor = get_migrate_executor() try: executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS]) diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py index 5e6b19c095..c28cf05c6a 100644 --- a/django/core/management/commands/migrate.py +++ b/django/core/management/commands/migrate.py @@ -7,9 +7,9 @@ from django.core.management.base import BaseCommand, CommandError, no_translatio from django.core.management.sql import emit_post_migrate_signal, emit_pre_migrate_signal from django.db import DEFAULT_DB_ALIAS, connections, router from django.db.migrations.autodetector import MigrationAutodetector -from django.db.migrations.executor import MigrationExecutor from django.db.migrations.loader import AmbiguityError from django.db.migrations.state import ModelState, ProjectState +from django.db.migrations.utils import get_migrate_executor from django.utils.module_loading import module_has_submodule from django.utils.text import Truncator @@ -115,6 +115,8 @@ class Command(BaseCommand): # Hook for backends needing any database preparation connection.prepare_database() # Work out which apps have migrations and which do not + + MigrationExecutor = get_migrate_executor() executor = MigrationExecutor(connection, self.migration_progress_callback) # Raise an error if any migrations are applied before their dependencies. diff --git a/django/db/migrations/utils.py b/django/db/migrations/utils.py index 6eb5a4c68f..544c228b74 100644 --- a/django/db/migrations/utils.py +++ b/django/db/migrations/utils.py @@ -3,6 +3,8 @@ import re from collections import namedtuple from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT +from django.utils.module_loading import import_string +from django.conf import settings FieldReference = namedtuple("FieldReference", "to through") @@ -127,3 +129,8 @@ def get_references(state, model_tuple, field_tuple=()): def field_is_referenced(state, model_tuple, field_tuple): """Return whether `field_tuple` is referenced by any state models.""" return next(get_references(state, model_tuple, field_tuple), None) is not None + + +def get_migrate_executor(): + """Returns the executor to use for migration.""" + return import_string(settings.MIGRATION_EXECUTOR_BACKEND)