| 1 |
from django.db import models |
|---|
| 2 |
from django.utils.translation import ugettext_lazy as _ |
|---|
| 3 |
from django.utils.encoding import smart_unicode |
|---|
| 4 |
|
|---|
| 5 |
class ContentTypeManager(models.Manager): |
|---|
| 6 |
|
|---|
| 7 |
# Cache to avoid re-looking up ContentType objects all over the place. |
|---|
| 8 |
# This cache is shared by all the get_for_* methods. |
|---|
| 9 |
_cache = {} |
|---|
| 10 |
|
|---|
| 11 |
def get_for_model(self, model): |
|---|
| 12 |
""" |
|---|
| 13 |
Returns the ContentType object for a given model, creating the |
|---|
| 14 |
ContentType if necessary. Lookups are cached so that subsequent lookups |
|---|
| 15 |
for the same model don't hit the database. |
|---|
| 16 |
""" |
|---|
| 17 |
opts = model._meta |
|---|
| 18 |
key = (opts.app_label, opts.object_name.lower()) |
|---|
| 19 |
try: |
|---|
| 20 |
ct = self.__class__._cache[key] |
|---|
| 21 |
except KeyError: |
|---|
| 22 |
# Load or create the ContentType entry. The smart_unicode() is |
|---|
| 23 |
# needed around opts.verbose_name_raw because name_raw might be a |
|---|
| 24 |
# django.utils.functional.__proxy__ object. |
|---|
| 25 |
ct, created = self.get_or_create( |
|---|
| 26 |
app_label = opts.app_label, |
|---|
| 27 |
model = opts.object_name.lower(), |
|---|
| 28 |
defaults = {'name': smart_unicode(opts.verbose_name_raw)}, |
|---|
| 29 |
) |
|---|
| 30 |
self._add_to_cache(ct) |
|---|
| 31 |
|
|---|
| 32 |
return ct |
|---|
| 33 |
|
|---|
| 34 |
def get_for_id(self, id): |
|---|
| 35 |
""" |
|---|
| 36 |
Lookup a ContentType by ID. Uses the same shared cache as get_for_model |
|---|
| 37 |
(though ContentTypes are obviously not created on-the-fly by get_by_id). |
|---|
| 38 |
""" |
|---|
| 39 |
try: |
|---|
| 40 |
ct = self.__class__._cache[id] |
|---|
| 41 |
except KeyError: |
|---|
| 42 |
# This could raise a DoesNotExist; that's correct behavior and will |
|---|
| 43 |
# make sure that only correct ctypes get stored in the cache dict. |
|---|
| 44 |
ct = self.get(pk=id) |
|---|
| 45 |
self._add_to_cache(ct) |
|---|
| 46 |
return ct |
|---|
| 47 |
|
|---|
| 48 |
def clear_cache(self): |
|---|
| 49 |
""" |
|---|
| 50 |
Clear out the content-type cache. This needs to happen during database |
|---|
| 51 |
flushes to prevent caching of "stale" content type IDs (see |
|---|
| 52 |
django.contrib.contenttypes.management.update_contenttypes for where |
|---|
| 53 |
this gets called). |
|---|
| 54 |
""" |
|---|
| 55 |
self.__class__._cache.clear() |
|---|
| 56 |
|
|---|
| 57 |
def _add_to_cache(self, ct): |
|---|
| 58 |
"""Insert a ContentType into the cache.""" |
|---|
| 59 |
model = ct.model_class() |
|---|
| 60 |
key = (model._meta.app_label, model._meta.object_name.lower()) |
|---|
| 61 |
self.__class__._cache[key] = ct |
|---|
| 62 |
self.__class__._cache[ct.id] = ct |
|---|
| 63 |
|
|---|
| 64 |
class ContentType(models.Model): |
|---|
| 65 |
name = models.CharField(max_length=100) |
|---|
| 66 |
app_label = models.CharField(max_length=100) |
|---|
| 67 |
model = models.CharField(_('python model class name'), max_length=100) |
|---|
| 68 |
objects = ContentTypeManager() |
|---|
| 69 |
|
|---|
| 70 |
class Meta: |
|---|
| 71 |
verbose_name = _('content type') |
|---|
| 72 |
verbose_name_plural = _('content types') |
|---|
| 73 |
db_table = 'django_content_type' |
|---|
| 74 |
ordering = ('name',) |
|---|
| 75 |
unique_together = (('app_label', 'model'),) |
|---|
| 76 |
|
|---|
| 77 |
def __unicode__(self): |
|---|
| 78 |
return self.name |
|---|
| 79 |
|
|---|
| 80 |
def model_class(self): |
|---|
| 81 |
"Returns the Python model class for this type of content." |
|---|
| 82 |
from django.db import models |
|---|
| 83 |
return models.get_model(self.app_label, self.model) |
|---|
| 84 |
|
|---|
| 85 |
def get_object_for_this_type(self, **kwargs): |
|---|
| 86 |
""" |
|---|
| 87 |
Returns an object of this type for the keyword arguments given. |
|---|
| 88 |
Basically, this is a proxy around this object_type's get_object() model |
|---|
| 89 |
method. The ObjectNotExist exception, if thrown, will not be caught, |
|---|
| 90 |
so code that calls this method should catch it. |
|---|
| 91 |
""" |
|---|
| 92 |
return self.model_class()._default_manager.get(**kwargs) |
|---|