You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

remove_stale_contenttypes.py 3.2KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. from django.apps import apps
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.core.management import BaseCommand
  4. from django.db import DEFAULT_DB_ALIAS, router
  5. from django.db.models.deletion import Collector
  6. from ...management import get_contenttypes_and_models
  7. class Command(BaseCommand):
  8. def add_arguments(self, parser):
  9. parser.add_argument(
  10. '--noinput', '--no-input', action='store_false', dest='interactive',
  11. help='Tells Django to NOT prompt the user for input of any kind.',
  12. )
  13. parser.add_argument(
  14. '--database', default=DEFAULT_DB_ALIAS,
  15. help='Nominates the database to use. Defaults to the "default" database.',
  16. )
  17. def handle(self, **options):
  18. db = options['database']
  19. interactive = options['interactive']
  20. verbosity = options['verbosity']
  21. for app_config in apps.get_app_configs():
  22. content_types, app_models = get_contenttypes_and_models(app_config, db, ContentType)
  23. to_remove = [
  24. ct for (model_name, ct) in content_types.items()
  25. if model_name not in app_models
  26. ]
  27. # Confirm that the content type is stale before deletion.
  28. using = router.db_for_write(ContentType)
  29. if to_remove:
  30. if interactive:
  31. ct_info = []
  32. for ct in to_remove:
  33. ct_info.append(' - Content type for %s.%s' % (ct.app_label, ct.model))
  34. collector = NoFastDeleteCollector(using=using)
  35. collector.collect([ct])
  36. for obj_type, objs in collector.data.items():
  37. if objs != {ct}:
  38. ct_info.append(' - %s %s object(s)' % (
  39. len(objs),
  40. obj_type._meta.label,
  41. ))
  42. content_type_display = '\n'.join(ct_info)
  43. self.stdout.write("""Some content types in your database are stale and can be deleted.
  44. Any objects that depend on these content types will also be deleted.
  45. The content types and dependent objects that would be deleted are:
  46. %s
  47. This list doesn't include any cascade deletions to data outside of Django's
  48. models (uncommon).
  49. Are you sure you want to delete these content types?
  50. If you're unsure, answer 'no'.\n""" % content_type_display)
  51. ok_to_delete = input("Type 'yes' to continue, or 'no' to cancel: ")
  52. else:
  53. ok_to_delete = 'yes'
  54. if ok_to_delete == 'yes':
  55. for ct in to_remove:
  56. if verbosity >= 2:
  57. self.stdout.write("Deleting stale content type '%s | %s'" % (ct.app_label, ct.model))
  58. ct.delete()
  59. else:
  60. if verbosity >= 2:
  61. self.stdout.write("Stale content types remain.")
  62. class NoFastDeleteCollector(Collector):
  63. def can_fast_delete(self, *args, **kwargs):
  64. """
  65. Always load related objects to display them when showing confirmation.
  66. """
  67. return False