From 7c27f3e7baeb5393aeb06c476fdb52ea3a7cdc65 Mon Sep 17 00:00:00 2001
From: Malcolm Tredinnick <malcolm.tredinnick@gmail.com>
Date: Sat, 15 Sep 2007 15:06:32 +0000
Subject: [PATCH] Fixed #5177 -- Changed content type creation to also remove
 the types for any orphaned entries (so it's now an "update" feature). Thanks,
 Rob Hudson.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6287 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 AUTHORS                                   |  1 +
 django/contrib/contenttypes/management.py | 33 ++++++++++++++---------
 django/contrib/contenttypes/models.py     |  2 +-
 3 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 7a4faea532..d2b31ff19b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -149,6 +149,7 @@ answer newbie questions, and generally made Django that much better:
     Sung-Jin Hong <serialx.net@gmail.com>
     Richard House <Richard.House@i-logue.com>
     Robert Rock Howard <http://djangomojo.com/>
+    Rob Hudson <http://rob.cogit8.org/>
     Jason Huggins <http://www.jrandolph.com/blog/>
     Hyun Mi Ae
     Tom Insam
diff --git a/django/contrib/contenttypes/management.py b/django/contrib/contenttypes/management.py
index cb52e0805e..49083d6d5c 100644
--- a/django/contrib/contenttypes/management.py
+++ b/django/contrib/contenttypes/management.py
@@ -1,34 +1,43 @@
-"""
-Creates content types for all installed models.
-"""
-
+from django.contrib.contenttypes.models import ContentType
 from django.dispatch import dispatcher
 from django.db.models import get_apps, get_models, signals
 from django.utils.encoding import smart_unicode
 
-def create_contenttypes(app, created_models, verbosity=2):
-    from django.contrib.contenttypes.models import ContentType
+def update_contenttypes(app, created_models, verbosity=2):
+    """
+    Creates content types for models in the given app, removing any model
+    entries that no longer have a matching model class.
+    """
     ContentType.objects.clear_cache()
+    content_types = list(ContentType.objects.filter(app_label=app.__name__.split('.')[-2]))
     app_models = get_models(app)
     if not app_models:
         return
     for klass in app_models:
         opts = klass._meta
         try:
-            ContentType.objects.get(app_label=opts.app_label,
-                model=opts.object_name.lower())
+            ct = ContentType.objects.get(app_label=opts.app_label,
+                                         model=opts.object_name.lower())
+            content_types.remove(ct)
         except ContentType.DoesNotExist:
             ct = ContentType(name=smart_unicode(opts.verbose_name_raw),
                 app_label=opts.app_label, model=opts.object_name.lower())
             ct.save()
             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()
 
-def create_all_contenttypes(verbosity=2):
+def update_all_contenttypes(verbosity=2):
     for app in get_apps():
-        create_contenttypes(app, None, verbosity)
+        update_contenttypes(app, None, verbosity)
 
-dispatcher.connect(create_contenttypes, signal=signals.post_syncdb)
+dispatcher.connect(update_contenttypes, signal=signals.post_syncdb)
 
 if __name__ == "__main__":
-    create_all_contenttypes()
+    update_all_contenttypes()
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index cda47a18aa..1413586254 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -25,7 +25,7 @@ class ContentTypeManager(models.Manager):
         """
         Clear out the content-type cache. This needs to happen during database
         flushes to prevent caching of "stale" content type IDs (see
-        django.contrib.contenttypes.management.create_contenttypes for where
+        django.contrib.contenttypes.management.update_contenttypes for where
         this gets called).
         """
         global CONTENT_TYPE_CACHE