Commit d29d11b0 authored by dani poni's avatar dani poni Committed by Tim Graham
Browse files

Fixed #26085 -- Fixed contenttypes shortcut() view crash with a null fk to Site.

Thanks Fabien Schwob for the initial patch.
parent e494b9ff
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -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

+22 −0
Original line number Diff line number Diff line
@@ -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)
+20 −2
Original line number Diff line number Diff line
@@ -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