django / django/new-features

Enhance showmigrations command with structured data collection and display separation

Open
#75 8 comments 9 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.