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
This commit is contained in:
parent
cb4a018c35
commit
54d5b9ec87
|
@ -39,13 +39,19 @@ class GenericForeignKey(object):
|
||||||
# content-type/object-id fields.
|
# content-type/object-id fields.
|
||||||
if self.name in kwargs:
|
if self.name in kwargs:
|
||||||
value = kwargs.pop(self.name)
|
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()
|
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
|
# Convenience function using get_model avoids a circular import when using this model
|
||||||
ContentType = get_model("contenttypes", "contenttype")
|
ContentType = get_model("contenttypes", "contenttype")
|
||||||
|
if obj:
|
||||||
return ContentType.objects.get_for_model(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):
|
def __get__(self, instance, instance_type=None):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
|
@ -55,8 +61,15 @@ class GenericForeignKey(object):
|
||||||
return getattr(instance, self.cache_attr)
|
return getattr(instance, self.cache_attr)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
rel_obj = None
|
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:
|
try:
|
||||||
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
|
rel_obj = ct.get_object_for_this_type(pk=getattr(instance, self.fk_field))
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
|
@ -71,7 +84,7 @@ class GenericForeignKey(object):
|
||||||
ct = None
|
ct = None
|
||||||
fk = None
|
fk = None
|
||||||
if value is not None:
|
if value is not None:
|
||||||
ct = self.get_content_type(value)
|
ct = self.get_content_type(obj=value)
|
||||||
fk = value._get_pk_val()
|
fk = value._get_pk_val()
|
||||||
|
|
||||||
setattr(instance, self.ct_field, ct)
|
setattr(instance, self.ct_field, ct)
|
||||||
|
|
Loading…
Reference in New Issue