Skip to content

Instantly share code, notes, and snippets.

@quevon24
Created August 26, 2025 23:23
Show Gist options
  • Save quevon24/98b80d33742b317b3ccecd6f476b4722 to your computer and use it in GitHub Desktop.
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.
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