From 6fa62b8166f00d6cf1160b84dce37416f0051f00 Mon Sep 17 00:00:00 2001 From: Julien Phalip Date: Mon, 2 Jan 2012 18:02:47 +0000 Subject: [PATCH] Fixed #8997 -- Prevented the contenttypes `shortcut` view to hide errors occurring inside the `get_absolute_url()` method. Thanks to Rob for the report and to joshlory, Aymeric Augustin and Claude Paroz for the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@17328 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/contenttypes/tests.py | 23 +++++++++++++++++++++++ django/contrib/contenttypes/views.py | 19 +++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/django/contrib/contenttypes/tests.py b/django/contrib/contenttypes/tests.py index 18546647558bb..f2a338e1d4924 100644 --- a/django/contrib/contenttypes/tests.py +++ b/django/contrib/contenttypes/tests.py @@ -30,6 +30,13 @@ class FooWithUrl(FooWithoutUrl): def get_absolute_url(self): return "/users/%s/" % urllib.quote(smart_str(self.name)) +class FooWithBrokenAbsoluteUrl(FooWithoutUrl): + """ + Fake model defining a ``get_absolute_url`` method containing an error + """ + + def get_absolute_url(self): + return "/users/%s/" % self.unknown_field class ContentTypesTests(TestCase): @@ -135,6 +142,22 @@ def test_shortcut_view_without_get_absolute_url(self): self.assertRaises(Http404, shortcut, request, user_ct.id, obj.id) + def test_shortcut_view_with_broken_get_absolute_url(self): + """ + Check that the shortcut view does not catch an AttributeError raised + by the model's get_absolute_url method. + Refs #8997. + """ + request = HttpRequest() + request.META = { + "SERVER_NAME": "Example.com", + "SERVER_PORT": "80", + } + user_ct = ContentType.objects.get_for_model(FooWithBrokenAbsoluteUrl) + obj = FooWithBrokenAbsoluteUrl.objects.create(name="john") + + self.assertRaises(AttributeError, shortcut, request, user_ct.id, obj.id) + def test_missing_model(self): """ Ensures that displaying content types in admin (or anywhere) doesn't diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py index ac0feffe7a0d5..5085a2fa2c0ff 100644 --- a/django/contrib/contenttypes/views.py +++ b/django/contrib/contenttypes/views.py @@ -4,19 +4,25 @@ from django.core.exceptions import ObjectDoesNotExist def shortcut(request, content_type_id, object_id): - "Redirect to an object's page based on a content-type ID and an object ID." + """ + Redirect to an object's page based on a content-type ID and an object ID. + """ # Look up the object, making sure it's got a get_absolute_url() function. try: content_type = ContentType.objects.get(pk=content_type_id) if not content_type.model_class(): - raise http.Http404("Content type %s object has no associated model" % content_type_id) + raise http.Http404("Content type %s object has no associated model" + % content_type_id) obj = content_type.get_object_for_this_type(pk=object_id) except (ObjectDoesNotExist, ValueError): - raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id)) + raise http.Http404("Content type %s object %s doesn't exist" + % (content_type_id, object_id)) try: - absurl = obj.get_absolute_url() + get_absolute_url = obj.get_absolute_url except AttributeError: - raise http.Http404("%s objects don't have get_absolute_url() methods" % content_type.name) + raise http.Http404("%s objects don't have a get_absolute_url() method" + % content_type.name) + absurl = get_absolute_url() # Try to figure out the object's domain, so we can do a cross-site redirect # if necessary. @@ -66,6 +72,7 @@ def shortcut(request, content_type_id, object_id): # to whatever get_absolute_url() returned. if object_domain is not None: protocol = request.is_secure() and 'https' or 'http' - return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl)) + return http.HttpResponseRedirect('%s://%s%s' + % (protocol, object_domain, absurl)) else: return http.HttpResponseRedirect(absurl)