Allow migrate command subclasses to customize the migration executor
- Dominant language
- No language data
- Stars
- 188
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
### Code of Conduct
- [x] I agree to follow Django's Code of Conduct
### Feature Description
Add an `executor_class` attribute to the migrate management command, defaulting to MigrationExecutor, so subclasses can customize migration execution without overriding the full command implementation.
This would follow the existing migration command pattern used by attributes such as autodetector.
### Problem
The migrate command currently instantiates MigrationExecutor directly inside its implementation.
This makes customization difficult for projects or third-party packages that need a custom migration executor.
Today, the practical workaround is to subclass the migrate command and copy large parts of handle() just to replace the executor construction line.
That approach is fragile because the copied logic can drift from Django upstream over time. It also makes small customizations unnecessarily expensive to maintain.
This feature would provide a small, explicit extension point while preserving the current default behavior.
### Request or proposal
proposal
### Additional Details
The proposed change is backwards compatible.
Existing behavior would remain unchanged because `executor_class` would default to MigrationExecutor.
The intended usage would be:
from django.core.management.commands.migrate import Command as MigrateCommand
from .executors import CustomMigrationExecutor
```
class Command(MigrateCommand):
executor_class = CustomMigrationExecutor
```
This is useful for projects that need to customize migration execution behavior while still relying on Django’s standard migrate command flow.
The change also aligns with the existing composition-style pattern used in Django’s migration commands, where collaborators can be exposed as class attributes rather than hard-coded directly inside command methods.
### Implementation Suggestions
Add a class-level attribute to django.core.management.commands.migrate.Command:
```
class Command(BaseCommand):
executor_class = MigrationExecutor
```
Then replace direct MigrationExecutor construction with self.executor_class.
For example:
`executor = self.executor_class(connection, self.migration_progress_callback)`
For consistency, BaseCommand.check_migrations() could also resolve the executor class from the command instance when available:
```
executor_class = getattr(self, "executor_class", MigrationExecutor)
executor = executor_class(connections[DEFAULT_DB_ALIAS])
```
Tests should cover:
- migrate.Command.executor_class defaults to MigrationExecutor
- migrate.Command.handle() uses self.executor_class
- BaseCommand.check_migrations() respects a custom executor_class
- existing behavior remains unchanged when executor_class is not overridden
Documentation should mention that subclasses of the migrate command may override executor_class to customize migration execution behavior.
POC:
https://github.com/django/django/pull/21358
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.