From d29d11b026e8acea4778dd596aaf82d55b11f44d Mon Sep 17 00:00:00 2001 From: dani poni <459630@gmail.com> Date: Sat, 16 Apr 2016 09:16:48 +0200 Subject: [PATCH] Fixed #26085 -- Fixed contenttypes shortcut() view crash with a null fk to Site. Thanks Fabien Schwob for the initial patch. --- django/contrib/contenttypes/views.py | 6 ++++-- tests/contenttypes_tests/models.py | 22 ++++++++++++++++++++++ tests/contenttypes_tests/tests.py | 22 ++++++++++++++++++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py index e99459e4f2..3957788d0e 100644 --- a/django/contrib/contenttypes/views.py +++ b/django/contrib/contenttypes/views.py @@ -63,9 +63,11 @@ def shortcut(request, content_type_id, object_id): for field in obj._meta.fields: if field.remote_field and field.remote_field.model is Site: try: - object_domain = getattr(obj, field.name).domain + site = getattr(obj, field.name) except Site.DoesNotExist: - pass + continue + if site is not None: + object_domain = site.domain if object_domain is not None: break diff --git a/tests/contenttypes_tests/models.py b/tests/contenttypes_tests/models.py index a302fe97f0..4b9d3d31e6 100644 --- a/tests/contenttypes_tests/models.py +++ b/tests/contenttypes_tests/models.py @@ -4,11 +4,21 @@ from django.contrib.contenttypes.fields import ( GenericForeignKey, GenericRelation, ) from django.contrib.contenttypes.models import ContentType +from django.contrib.sites.models import SiteManager from django.db import models from django.utils.encoding import python_2_unicode_compatible from django.utils.http import urlquote +@python_2_unicode_compatible +class Site(models.Model): + domain = models.CharField(max_length=100) + objects = SiteManager() + + def __str__(self): + return self.domain + + @python_2_unicode_compatible class Author(models.Model): name = models.CharField(max_length=100) @@ -115,3 +125,15 @@ class Post(models.Model): def __str__(self): return self.title + + +@python_2_unicode_compatible +class ModelWithNullFKToSite(models.Model): + title = models.CharField(max_length=200) + site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE) + + def __str__(self): + return self.title + + def get_absolute_url(self): + return '/title/%s/' % urlquote(self.title) diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py index c2377bf82e..a494df0340 100644 --- a/tests/contenttypes_tests/tests.py +++ b/tests/contenttypes_tests/tests.py @@ -12,11 +12,14 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site from django.core import checks from django.db import connections, models -from django.test import SimpleTestCase, TestCase, override_settings +from django.test import SimpleTestCase, TestCase, mock, override_settings from django.test.utils import captured_stdout, isolate_apps from django.utils.encoding import force_str, force_text -from .models import Article, Author, SchemeIncludedURL +from .models import ( + Article, Author, ModelWithNullFKToSite, SchemeIncludedURL, + Site as MockSite, +) @override_settings(ROOT_URLCONF='contenttypes_tests.urls') @@ -94,6 +97,21 @@ class ContentTypesViewsTests(TestCase): response = self.client.get(short_url) self.assertEqual(response.status_code, 404) + @mock.patch('django.apps.apps.get_model') + def test_shortcut_view_with_null_site_fk(self, get_model): + """ + The shortcut view works if a model's ForeignKey to site is None. + """ + get_model.side_effect = lambda *args, **kwargs: MockSite if args[0] == 'sites.Site' else ModelWithNullFKToSite + + obj = ModelWithNullFKToSite.objects.create(title='title') + url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(ModelWithNullFKToSite).id, obj.pk) + response = self.client.get(url) + self.assertRedirects( + response, '%s' % obj.get_absolute_url(), + fetch_redirect_response=False, + ) + def test_create_contenttype_on_the_spot(self): """ Make sure ContentTypeManager.get_for_model creates the corresponding