From 45a56e637ea5e356b2f276a7ddbb4335f3c39b35 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee <russell@keith-magee.com>
Date: Mon, 15 Mar 2010 09:57:57 +0000
Subject: [PATCH] Fixed #12339 -- Made content type deletion an interactive
 process to prevent accidentally cascade deleting content from a production
 database. Thanks to kcarnold for the report and patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12782 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/contrib/contenttypes/management.py | 34 +++++++++++++++++------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/django/contrib/contenttypes/management.py b/django/contrib/contenttypes/management.py
index 736e213665..27d12751f2 100644
--- a/django/contrib/contenttypes/management.py
+++ b/django/contrib/contenttypes/management.py
@@ -25,16 +25,34 @@ def update_contenttypes(app, created_models, verbosity=2, **kwargs):
             if verbosity >= 2:
                 print "Adding content type '%s | %s'" % (ct.app_label, ct.model)
     # The presence of any remaining content types means the supplied app has an
-    # undefined model and can safely be removed, which cascades to also remove
-    # related permissions.
-    for ct in content_types:
-        if verbosity >= 2:
-            print "Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)
-        ct.delete()
+    # undefined model. Confirm that the content type is stale before deletion.
+    if content_types:
+        if kwargs.get('interactive', False):
+            content_type_display = '\n'.join(['    %s | %s' % (ct.app_label, ct.model) for ct in content_types])
+            ok_to_delete = raw_input("""The following content types are stale and need to be deleted:
 
-def update_all_contenttypes(verbosity=2):
+%s
+
+Any objects related to these content types by a foreign key will also
+be deleted. Are you sure you want to delete these content types?
+If you're unsure, answer 'no'.
+
+    Type 'yes' to continue, or 'no' to cancel: """ % content_type_display)
+        else:
+            ok_to_delete = False
+
+        if ok_to_delete == 'yes':
+            for ct in content_types:
+                if verbosity >= 2:
+                    print "Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)
+                ct.delete()
+        else:
+            if verbosity >= 2:
+                print "Stale content types remain."
+
+def update_all_contenttypes(verbosity=2, **kwargs):
     for app in get_apps():
-        update_contenttypes(app, None, verbosity)
+        update_contenttypes(app, None, verbosity, **kwargs)
 
 signals.post_syncdb.connect(update_contenttypes)