1
0
mirror of https://github.com/django/django.git synced 2025-04-26 10:14:36 +00:00

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: for field in obj._meta.fields:
if field.remote_field and field.remote_field.model is Site: if field.remote_field and field.remote_field.model is Site:
try: try:
object_domain = getattr(obj, field.name).domain site = getattr(obj, field.name)
except Site.DoesNotExist: except Site.DoesNotExist:
pass continue
if site is not None:
object_domain = site.domain
if object_domain is not None: if object_domain is not None:
break break

View File

@ -4,11 +4,21 @@ from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation, GenericForeignKey, GenericRelation,
) )
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import SiteManager
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.http import urlquote 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 @python_2_unicode_compatible
class Author(models.Model): class Author(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
@ -115,3 +125,15 @@ class Post(models.Model):
def __str__(self): def __str__(self):
return self.title 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.contrib.sites.models import Site
from django.core import checks from django.core import checks
from django.db import connections, models 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.test.utils import captured_stdout, isolate_apps
from django.utils.encoding import force_str, force_text 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') @override_settings(ROOT_URLCONF='contenttypes_tests.urls')
@ -94,6 +97,21 @@ class ContentTypesViewsTests(TestCase):
response = self.client.get(short_url) response = self.client.get(short_url)
self.assertEqual(response.status_code, 404) 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): def test_create_contenttype_on_the_spot(self):
""" """
Make sure ContentTypeManager.get_for_model creates the corresponding Make sure ContentTypeManager.get_for_model creates the corresponding