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

Thanks Fabien Schwob for the initial patch.
This commit is contained in:
dani poni 2016-04-16 09:16:48 +02:00 committed by Tim Graham
parent e494b9ffb6
commit d29d11b026
3 changed files with 46 additions and 4 deletions

View File

@ -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

View File

@ -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)

View File

@ -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