Enhance showmigrations command with structured data collection and display separation
- 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
Enhance the `showmigrations` command with structured data collection and display separation
Add a `get_migration_data()` method to the `showmigrations` command that returns migration data in a structured format, and modify `show_list()` to accept this data as a parameter. This separation enables better extensibility and customization while preserving all existing functionality.
### Problem
The current `showmigrations` command tightly couples data collection with display logic, making it difficult to extend or customize the output format. Third-party packages and custom commands cannot easily access migration data in a structured format or customize the display without duplicating Django's internal logic.
**Why Not Just Create a Custom Command?**
While it's possible to create a custom command for specific needs, many use cases align closely with `showmigrations` functionality. Creating separate commands leads to:
- **Code Duplication:** Replicating Django's migration loading and graph traversal logic
- **Maintenance Burden:** Keeping custom commands in sync with Django's internal changes
- **Fragmentation:** Multiple similar commands across the ecosystem
- **Lost Benefits:** Missing Django's built-in features (app filtering, verbosity, etc.)
This enhancement would benefit the entire Django ecosystem by making `showmigrations` more extensible while preserving its core functionality.
### Request or proposal
proposal
### Additional Details
**Proposed Solution:**
Separate data collection from display logic by introducing a `get_migration_data()` method that returns structured migration data, and modify `show_list()` to accept this data as a parameter.
**Benefits:**
- **Extensibility:** Third-party packages can easily access migration data
- **Testability:** Data collection and display can be tested independently
- **Maintainability:** Cleaner separation of concerns
- **Reusability:** Migration data can be used by other methods
- **Ecosystem Health:** Reduces code duplication across Django packages
- **Output Flexibility:** Complete control over how the `showmigration` result is displayed
**Proposed API:**
```
class Command(BaseCommand):
def handle(self, *args, **options):
self.verbosity = options["verbosity"]
if options["format"] == "plan":
# We can apply a similar approach to the plan, also.
return self.show_plan(connection, options["app_label"])
else:
migration_data = self.get_migration_data(connection, options["app_label"])
return self.show_list(migration_data)
def get_migration_data(self, connection, app_names=None):
"""
Return migration data in structured format.
Returns:
dict: {"app_name": [{"name": "0001_initial", "applied": True, ...}, ...]}
"""
# Current show_list logic moved here, but returns data instead of printing
pass
def show_list(self, migration_data):
"""
Display migration data using provided data.
Args:
migration_data (dict): Migration data from get_migration_data()
"""
# Display logic using migration_data parameter
pass
```
`get_migration_data` return data structure
```
{
"app_name": [
{"name": "0001_initial", "applied": True, ...},
{"name": "0002_add_field", "applied": False, ...},
# ...
],
# ...
}
```
### Implementation Suggestions
**Implementation Notes:**
- `get_migration_data()` should contain the current `show_list()` logic but return data instead of printing
- `show_list()` should be refactored to use the data parameter
- Both methods should be easily overridable by subclasses
**Example Usage:**
```
# Custom command extending showmigrations
class CustomShowMigrationsCommand(ShowMigrationsCommand):
def get_migration_data(self, connection, app_names=None):
data = super().get_migration_data(connection, app_names)
# Add custom data (e.g., file sizes, creation dates, etc.), maybe based on some custom flags
for app_name, migrations in data.items():
for migration in migrations:
migration_file = self.find_migration_file(app_name, migration["name"])
if migration_file:
migration["file_size"] = migration_file.stat().st_size
migration["created_at"] = migration_file.stat().st_ctime
return data
def show_list(self, migration_data):
# Custom display format with file sizes
for app_name, migrations in migration_data.items():
for migration in migrations:
status = "✓" if migration["applied"] else "✗"
file_size = migration.get("file_size", 0)
self.stdout.write(f" {status} {app_name}.{migration['name']} ({file_size} bytes)")
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.