summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Kaplan-Moss <jacob@jacobian.org>2008-03-12 00:09:13 +0000
committerJacob Kaplan-Moss <jacob@jacobian.org>2008-03-12 00:09:13 +0000
commit54d5b9ec87b9a4e6da7bd9fec99ce0ba2f9fb44a (patch)
treebc8ad9198c582cf5105b8e9ee83ad48896f9569d
parentcb4a018c35c0b4e3d8ad98d7664bfd309ec7c82c (diff)
Fixed #5570: generic foreign keys no longer do multiple lookups on the content type. This uses the new ctype caching bit added in [7216].
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7228 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/contenttypes/generic.py25
1 files changed, 19 insertions, 6 deletions
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index e496ed1af8..25cef95acf 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -39,13 +39,19 @@ class GenericForeignKey(object):
# content-type/object-id fields.
if self.name in kwargs:
value = kwargs.pop(self.name)
- kwargs[self.ct_field] = self.get_content_type(value)
+ kwargs[self.ct_field] = self.get_content_type(obj=value)
kwargs[self.fk_field] = value._get_pk_val()
- def get_content_type(self, obj):
+ def get_content_type(self, obj=None, id=None):
# Convenience function using get_model avoids a circular import when using this model
ContentType = get_model("contenttypes", "contenttype")
- return ContentType.objects.get_for_model(obj)
+ if obj:
+ return ContentType.objects.get_for_model(obj)
+ elif id:
+ return ContentType.objects.get_for_id(id)
+ else:
+ # This should never happen. I love comments like this, don't you?
+ raise Exception("Impossible arguments to GFK.get_content_type!")
def __get__(self, instance, instance_type=None):
if instance is None:
@@ -55,8 +61,15 @@ class GenericForeignKey(object):
return getattr(instance, self.cache_attr)
except AttributeError:
rel_obj = None
- ct = getattr(instance, self.ct_field)
- if ct:
+
+ # Make sure to use ContentType.objects.get_for_id() to ensure that
+ # lookups are cached (see ticket #5570). This takes more code than
+ # the naive ``getattr(instance, self.ct_field)``, but has better
+ # performance when dealing with GFKs in loops and such.
+ f = self.model._meta.get_field(self.ct_field)
+ ct_id = getattr(instance, f.get_attname(), None)
+ if ct_id:
+ ct = self.get_content_type(id=ct_id)
try:
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
except ObjectDoesNotExist:
@@ -71,7 +84,7 @@ class GenericForeignKey(object):
ct = None
fk = None
if value is not None:
- ct = self.get_content_type(value)
+ ct = self.get_content_type(obj=value)
fk = value._get_pk_val()
setattr(instance, self.ct_field, ct)