Created
August 26, 2025 23:23
-
-
Save quevon24/98b80d33742b317b3ccecd6f476b4722 to your computer and use it in GitHub Desktop.
Command to list models related to a given model grouped by the on_delete behavior. Useful if you want to figure out what will happen if you delete an instance of a model.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.management.base import BaseCommand | |
from django.apps import apps | |
from django.db.models import ForeignKey, OneToOneField | |
class Command(BaseCommand): | |
""" | |
Command to list models related to a given model grouped by the on_delete behavior. | |
It shows which models have relationships with the target model and groups them | |
by the type of on_delete action (CASCADE, SET_NULL, DO_NOTHING, etc.) along with | |
a description of what that action means. | |
Usage: | |
python manage.py relations app_label.ModelName | |
""" | |
ON_DELETE_DESCRIPTIONS = { | |
'CASCADE': 'Deletes related instances when the primary instance is deleted.', | |
'SET_NULL': 'Sets the related field to NULL when the primary instance is deleted (field must be nullable).', | |
'DO_NOTHING': 'Does nothing automatically; manual handling required and may cause errors if database constraints are violated.', | |
'PROTECT': 'Prevents deletion if related objects exist, raises integrity error.', | |
'SET_DEFAULT': 'Sets the related field to its default value when the primary instance is deleted.', | |
'RESTRICT': 'Prevents deletion if related objects exist (similar to PROTECT).', | |
} | |
def add_arguments(self, parser): | |
parser.add_argument( | |
'model_name', | |
type=str, | |
help='Model name in the format app_label.ModelName' | |
) | |
def handle(self, *args, **options): | |
model_name = options['model_name'] | |
try: | |
app_label, model_class_name = model_name.split('.') | |
model = apps.get_model(app_label, model_class_name) | |
except (ValueError, LookupError): | |
self.stdout.write(self.style.ERROR(f'Model not found or incorrect format: {model_name}')) | |
return | |
grouped_models = {} | |
# Iterate all registered models to find fields pointing to the target model | |
for m in apps.get_models(): | |
for field in m._meta.get_fields(): | |
if isinstance(field, (ForeignKey, OneToOneField)): | |
# field.remote_field contains metadata about how the relationship is configured, including the | |
# target model, what to do on deletion | |
if field.remote_field and field.remote_field.model == model: | |
on_delete_action = field.remote_field.on_delete.__name__ | |
grouped_models.setdefault(on_delete_action, []).append(m._meta.label) | |
self.stdout.write(f'Relations for {model_name} grouped by on_delete type:\n') | |
if not grouped_models: | |
self.stdout.write('- (No specific on_delete relations found)') | |
return | |
# Print each on_delete group with description and related models | |
for action, models_list in sorted(grouped_models.items()): | |
description = self.ON_DELETE_DESCRIPTIONS.get(action, 'No description available.') | |
self.stdout.write(f'{action}:') | |
self.stdout.write(f' {description}') | |
for model_label in sorted(set(models_list)): | |
self.stdout.write(f'- {model_label}') | |
self.stdout.write('') | |
self.stdout.write(self.style.SUCCESS('Analysis completed.')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment