app/django/contrib/contenttypes/models.py
changeset 54 03e267d67478
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/contrib/contenttypes/models.py	Fri Jul 18 18:22:23 2008 +0000
@@ -0,0 +1,92 @@
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import smart_unicode
+
+class ContentTypeManager(models.Manager):
+
+    # Cache to avoid re-looking up ContentType objects all over the place.
+    # This cache is shared by all the get_for_* methods.
+    _cache = {}
+    
+    def get_for_model(self, model):
+        """
+        Returns the ContentType object for a given model, creating the
+        ContentType if necessary. Lookups are cached so that subsequent lookups
+        for the same model don't hit the database.
+        """
+        opts = model._meta
+        key = (opts.app_label, opts.object_name.lower())
+        try:
+            ct = self.__class__._cache[key]
+        except KeyError:
+            # Load or create the ContentType entry. The smart_unicode() is 
+            # needed around opts.verbose_name_raw because name_raw might be a
+            # django.utils.functional.__proxy__ object.
+            ct, created = self.get_or_create(
+                app_label = opts.app_label,
+                model = opts.object_name.lower(), 
+                defaults = {'name': smart_unicode(opts.verbose_name_raw)},
+            )
+            self._add_to_cache(ct)
+            
+        return ct
+        
+    def get_for_id(self, id):
+        """
+        Lookup a ContentType by ID. Uses the same shared cache as get_for_model
+        (though ContentTypes are obviously not created on-the-fly by get_by_id).
+        """
+        try:
+            ct = self.__class__._cache[id]
+        except KeyError:
+            # This could raise a DoesNotExist; that's correct behavior and will
+            # make sure that only correct ctypes get stored in the cache dict.
+            ct = self.get(pk=id)
+            self._add_to_cache(ct)
+        return ct
+            
+    def clear_cache(self):
+        """
+        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.update_contenttypes for where
+        this gets called).
+        """
+        self.__class__._cache.clear()
+        
+    def _add_to_cache(self, ct):
+        """Insert a ContentType into the cache."""
+        model = ct.model_class()
+        key = (model._meta.app_label, model._meta.object_name.lower())
+        self.__class__._cache[key] = ct
+        self.__class__._cache[ct.id] = ct
+
+class ContentType(models.Model):
+    name = models.CharField(max_length=100)
+    app_label = models.CharField(max_length=100)
+    model = models.CharField(_('python model class name'), max_length=100)
+    objects = ContentTypeManager()
+    
+    class Meta:
+        verbose_name = _('content type')
+        verbose_name_plural = _('content types')
+        db_table = 'django_content_type'
+        ordering = ('name',)
+        unique_together = (('app_label', 'model'),)
+
+    def __unicode__(self):
+        return self.name
+
+    def model_class(self):
+        "Returns the Python model class for this type of content."
+        from django.db import models
+        return models.get_model(self.app_label, self.model)
+
+    def get_object_for_this_type(self, **kwargs):
+        """
+        Returns an object of this type for the keyword arguments given.
+        Basically, this is a proxy around this object_type's get_object() model
+        method. The ObjectNotExist exception, if thrown, will not be caught,
+        so code that calls this method should catch it.
+        """
+        return self.model_class()._default_manager.get(**kwargs)