|
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) |