Kaydet (Commit) d14850e5 authored tarafından Paulo's avatar Paulo Kaydeden (comit) Tim Graham

Fixed #18620 -- Made ContentTypes shortcut view prefer current site if available.

Thanks Mike Tigas (mtigas) for the initial patch.
üst efbcd60a
from django.apps import apps from django.apps import apps
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.requests import RequestSite from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
...@@ -43,27 +43,32 @@ def shortcut(request, content_type_id, object_id): ...@@ -43,27 +43,32 @@ def shortcut(request, content_type_id, object_id):
# Otherwise, we need to introspect the object's relationships for a # Otherwise, we need to introspect the object's relationships for a
# relation to the Site object # relation to the Site object
object_domain = None try:
object_domain = get_current_site(request).domain
except ObjectDoesNotExist:
object_domain = None
if apps.is_installed('django.contrib.sites'): if apps.is_installed('django.contrib.sites'):
Site = apps.get_model('sites.Site') Site = apps.get_model('sites.Site')
opts = obj._meta opts = obj._meta
# First, look for a many-to-many relationship to Site.
for field in opts.many_to_many: for field in opts.many_to_many:
# Look for a many-to-many relationship to Site.
if field.remote_field.model is Site: if field.remote_field.model is Site:
try: site_qs = getattr(obj, field.name).all()
# Caveat: In the case of multiple related Sites, this just if object_domain and site_qs.filter(domain=object_domain).exists():
# selects the *first* one, which is arbitrary. # The current site's domain matches a site attached to the
object_domain = getattr(obj, field.name).all()[0].domain # object.
except IndexError:
pass
if object_domain is not None:
break break
# Caveat: In the case of multiple related Sites, this just
# Next, look for a many-to-one relationship to Site. # selects the *first* one, which is arbitrary.
if object_domain is None: site = site_qs.first()
if site:
object_domain = site.domain
break
else:
# No many-to-many relationship to Site found. Look for a
# many-to-one relationship to Site.
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:
...@@ -72,20 +77,8 @@ def shortcut(request, content_type_id, object_id): ...@@ -72,20 +77,8 @@ def shortcut(request, content_type_id, object_id):
continue continue
if site is not None: if site is not None:
object_domain = site.domain object_domain = site.domain
if object_domain is not None:
break break
# Fall back to the current site (if possible).
if object_domain is None:
try:
object_domain = Site.objects.get_current(request).domain
except Site.DoesNotExist:
pass
else:
# Fall back to the current request's site.
object_domain = RequestSite(request).domain
# If all that malarkey found an object domain, use it. Otherwise, fall back # If all that malarkey found an object domain, use it. Otherwise, fall back
# to whatever get_absolute_url() returned. # to whatever get_absolute_url() returned.
if object_domain is not None: if object_domain is not None:
......
...@@ -106,13 +106,15 @@ class ContentTypesViewsTests(TestCase): ...@@ -106,13 +106,15 @@ class ContentTypesViewsTests(TestCase):
obj = ModelWithNullFKToSite.objects.create(title='title') obj = ModelWithNullFKToSite.objects.create(title='title')
url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(ModelWithNullFKToSite).id, obj.pk) url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(ModelWithNullFKToSite).id, obj.pk)
response = self.client.get(url) response = self.client.get(url)
self.assertRedirects(response, '%s' % obj.get_absolute_url(), fetch_redirect_response=False) expected_url = 'http://testserver%s' % obj.get_absolute_url()
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
@mock.patch('django.apps.apps.get_model') @mock.patch('django.apps.apps.get_model')
def test_shortcut_view_with_site_m2m(self, get_model): def test_shortcut_view_with_site_m2m(self, get_model):
""" """
When the object has a ManyToManyField to Site, redirect to the When the object has a ManyToManyField to Site, redirect to the current
domain of the first site found in the m2m relationship. site if it's attached to the object or to the domain of the first site
found in the m2m relationship.
""" """
get_model.side_effect = lambda *args, **kwargs: MockSite if args[0] == 'sites.Site' else ModelWithM2MToSite get_model.side_effect = lambda *args, **kwargs: MockSite if args[0] == 'sites.Site' else ModelWithM2MToSite
...@@ -138,6 +140,23 @@ class ContentTypesViewsTests(TestCase): ...@@ -138,6 +140,23 @@ class ContentTypesViewsTests(TestCase):
response = self.client.get('/shortcut/%s/%s/' % (ct.pk, site_3_obj.pk)) response = self.client.get('/shortcut/%s/%s/' % (ct.pk, site_3_obj.pk))
self.assertRedirects(response, expected_url, fetch_redirect_response=False) self.assertRedirects(response, expected_url, fetch_redirect_response=False)
obj_with_sites = ModelWithM2MToSite.objects.create(title='Linked to Current Site')
obj_with_sites.sites.set(MockSite.objects.all())
shortcut_url = '/shortcut/%s/%s/' % (ct.pk, obj_with_sites.pk)
expected_url = 'http://example2.com%s' % obj_with_sites.get_absolute_url()
with self.settings(SITE_ID=2):
# Redirects to the domain of the Site matching the current site's
# domain.
response = self.client.get(shortcut_url)
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
with self.settings(SITE_ID=None, ALLOWED_HOSTS=['example2.com']):
# Redirects to the domain of the Site matching the request's host
# header.
response = self.client.get(shortcut_url, SERVER_NAME='example2.com')
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
class ShortcutViewTests(TestCase): class ShortcutViewTests(TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment