summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2014-09-30 13:15:59 -0400
committerTim Graham <timograham@gmail.com>2014-10-01 16:23:20 -0400
commit32c7d3c061b83e9206ef2bf13fbc302a1998f317 (patch)
tree8b05e48a0c3cfb5a8a493287198bcaf32fdc817b /django
parent333960582170457473aafe24dbcb8502af7d8ffc (diff)
Fixed #15089 -- Allowed contrib.sites to lookup the current site based on request.get_host().
Thanks Claude Paroz, Riccardo Magliocchetti, and Damian Moore for contributions to the patch.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/contenttypes/views.py2
-rw-r--r--django/contrib/sites/middleware.py4
-rw-r--r--django/contrib/sites/models.py51
-rw-r--r--django/contrib/sites/shortcuts.py2
-rw-r--r--django/contrib/sites/tests.py41
5 files changed, 77 insertions, 23 deletions
diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py
index 6bc3aa04dd..02446d023a 100644
--- a/django/contrib/contenttypes/views.py
+++ b/django/contrib/contenttypes/views.py
@@ -72,7 +72,7 @@ def shortcut(request, content_type_id, object_id):
# Fall back to the current site (if possible).
if object_domain is None:
try:
- object_domain = Site.objects.get_current().domain
+ object_domain = Site.objects.get_current(request).domain
except Site.DoesNotExist:
pass
diff --git a/django/contrib/sites/middleware.py b/django/contrib/sites/middleware.py
index eb34d2ecdb..fdc7923581 100644
--- a/django/contrib/sites/middleware.py
+++ b/django/contrib/sites/middleware.py
@@ -1,4 +1,4 @@
-from .models import Site
+from .shortcuts import get_current_site
class CurrentSiteMiddleware(object):
@@ -7,4 +7,4 @@ class CurrentSiteMiddleware(object):
"""
def process_request(self, request):
- request.site = Site.objects.get_current()
+ request.site = get_current_site(request)
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index 0e80d9107a..9efba9bd5c 100644
--- a/django/contrib/sites/models.py
+++ b/django/contrib/sites/models.py
@@ -34,26 +34,39 @@ def _simple_domain_name_validator(value):
class SiteManager(models.Manager):
- def get_current(self):
+ def _get_site_by_id(self, site_id):
+ if site_id not in SITE_CACHE:
+ site = self.get(pk=site_id)
+ SITE_CACHE[site_id] = site
+ return SITE_CACHE[site_id]
+
+ def _get_site_by_request(self, request):
+ host = request.get_host()
+ if host not in SITE_CACHE:
+ site = self.get(domain__iexact=host)
+ SITE_CACHE[host] = site
+ return SITE_CACHE[host]
+
+ def get_current(self, request=None):
"""
- Returns the current ``Site`` based on the SITE_ID in the
- project's settings. The ``Site`` object is cached the first
- time it's retrieved from the database.
+ Returns the current Site based on the SITE_ID in the project's settings.
+ If SITE_ID isn't defined, it returns the site with domain matching
+ request.get_host(). The ``Site`` object is cached the first time it's
+ retrieved from the database.
"""
from django.conf import settings
- try:
- sid = settings.SITE_ID
- except AttributeError:
- raise ImproperlyConfigured(
- "You're using the Django \"sites framework\" without having "
- "set the SITE_ID setting. Create a site in your database and "
- "set the SITE_ID setting to fix this error.")
- try:
- current_site = SITE_CACHE[sid]
- except KeyError:
- current_site = self.get(pk=sid)
- SITE_CACHE[sid] = current_site
- return current_site
+ if getattr(settings, 'SITE_ID', ''):
+ site_id = settings.SITE_ID
+ return self._get_site_by_id(site_id)
+ elif request:
+ return self._get_site_by_request(request)
+
+ raise ImproperlyConfigured(
+ "You're using the Django \"sites framework\" without having "
+ "set the SITE_ID setting. Create a site in your database and "
+ "set the SITE_ID setting or pass a request to "
+ "Site.objects.get_current() to fix this error."
+ )
def clear_cache(self):
"""Clears the ``Site`` object cache."""
@@ -103,5 +116,9 @@ def clear_site_cache(sender, **kwargs):
del SITE_CACHE[instance.pk]
except KeyError:
pass
+ try:
+ del SITE_CACHE[Site.objects.get(pk=instance.pk).domain]
+ except (KeyError, Site.DoesNotExist):
+ pass
pre_save.connect(clear_site_cache, sender=Site)
pre_delete.connect(clear_site_cache, sender=Site)
diff --git a/django/contrib/sites/shortcuts.py b/django/contrib/sites/shortcuts.py
index c525948286..12471dc9a5 100644
--- a/django/contrib/sites/shortcuts.py
+++ b/django/contrib/sites/shortcuts.py
@@ -12,7 +12,7 @@ def get_current_site(request):
# the Site models when django.contrib.sites isn't installed.
if apps.is_installed('django.contrib.sites'):
from .models import Site
- return Site.objects.get_current()
+ return Site.objects.get_current(request)
else:
from .requests import RequestSite
return RequestSite(request)
diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py
index fadd4aa81d..94264b4af6 100644
--- a/django/contrib/sites/tests.py
+++ b/django/contrib/sites/tests.py
@@ -5,8 +5,9 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.http import HttpRequest
from django.test import TestCase, modify_settings, override_settings
+from . import models
from .middleware import CurrentSiteMiddleware
-from .models import Site
+from .models import clear_site_cache, Site
from .requests import RequestSite
from .shortcuts import get_current_site
@@ -15,7 +16,12 @@ from .shortcuts import get_current_site
class SitesFrameworkTests(TestCase):
def setUp(self):
- Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
+ self.site = Site(
+ id=settings.SITE_ID,
+ domain="example.com",
+ name="example.com",
+ )
+ self.site.save()
def test_save_another(self):
# Regression for #17415
@@ -71,6 +77,17 @@ class SitesFrameworkTests(TestCase):
self.assertIsInstance(site, RequestSite)
self.assertEqual(site.name, "example.com")
+ @override_settings(SITE_ID='', ALLOWED_HOSTS=['example.com'])
+ def test_get_current_site_no_site_id(self):
+ request = HttpRequest()
+ request.META = {
+ "SERVER_NAME": "example.com",
+ "SERVER_PORT": "80",
+ }
+ del settings.SITE_ID
+ site = get_current_site(request)
+ self.assertEqual(site.name, "example.com")
+
def test_domain_name_with_whitespaces(self):
# Regression for #17320
# Domain names are not allowed contain whitespace characters
@@ -81,6 +98,26 @@ class SitesFrameworkTests(TestCase):
site.domain = "test\ntest"
self.assertRaises(ValidationError, site.full_clean)
+ def test_clear_site_cache(self):
+ request = HttpRequest()
+ request.META = {
+ "SERVER_NAME": "example.com",
+ "SERVER_PORT": "80",
+ }
+ self.assertEqual(models.SITE_CACHE, {})
+ get_current_site(request)
+ expected_cache = {self.site.id: self.site}
+ self.assertEqual(models.SITE_CACHE, expected_cache)
+
+ with self.settings(SITE_ID=''):
+ get_current_site(request)
+
+ expected_cache.update({self.site.domain: self.site})
+ self.assertEqual(models.SITE_CACHE, expected_cache)
+
+ clear_site_cache(Site, instance=self.site)
+ self.assertEqual(models.SITE_CACHE, {})
+
class MiddlewareTest(TestCase):