From 03c6356c38d9a103835226ad7db479168bef29ae Mon Sep 17 00:00:00 2001
From: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
Date: Thu, 3 Apr 2014 20:15:53 +0200
Subject: [PATCH] Make settings.SITE_ID optional for django.contrib.sites
#15089
Using the request to do the Site matching.
Based on patch from Claude Peroz.
Signed-off-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
---
django/contrib/sites/models.py | 47 +++++++++++++++++++++++++--------------
django/contrib/sites/shortcuts.py | 4 +++-
django/contrib/sites/tests.py | 11 +++++++++
docs/ref/contrib/sites.txt | 17 ++++++++++----
4 files changed, 57 insertions(+), 22 deletions(-)
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index 0e80d91..ff9e9f2 100644
a
|
b
|
def _simple_domain_name_validator(value):
|
34 | 34 | |
35 | 35 | class SiteManager(models.Manager): |
36 | 36 | |
37 | | def get_current(self): |
| 37 | def _get_site_by_id(self, sid): |
| 38 | if not sid in SITE_CACHE: |
| 39 | site = self.get(pk=sid) |
| 40 | SITE_CACHE[sid] = site |
| 41 | return SITE_CACHE[sid] |
| 42 | |
| 43 | def _get_site_by_request(self, request): |
| 44 | host = request.get_host() |
| 45 | if not host in SITE_CACHE: |
| 46 | site = self.get(domain__iexact=host) |
| 47 | SITE_CACHE[host] = site |
| 48 | return SITE_CACHE[host] |
| 49 | |
| 50 | def get_current(self, request=None): |
38 | 51 | """ |
39 | 52 | Returns the current ``Site`` based on the SITE_ID in the |
40 | | project's settings. The ``Site`` object is cached the first |
41 | | time it's retrieved from the database. |
| 53 | project's settings if request is None. Otherwise return the |
| 54 | the current ``Site`` matching its domain with request's host |
| 55 | The ``Site`` object is cached the first time it's retrieved |
| 56 | from the database. |
42 | 57 | """ |
43 | | from django.conf import settings |
44 | | try: |
45 | | sid = settings.SITE_ID |
46 | | except AttributeError: |
47 | | raise ImproperlyConfigured( |
48 | | "You're using the Django \"sites framework\" without having " |
49 | | "set the SITE_ID setting. Create a site in your database and " |
50 | | "set the SITE_ID setting to fix this error.") |
51 | | try: |
52 | | current_site = SITE_CACHE[sid] |
53 | | except KeyError: |
54 | | current_site = self.get(pk=sid) |
55 | | SITE_CACHE[sid] = current_site |
56 | | return current_site |
| 58 | if request: |
| 59 | return self._get_site_by_request(request) |
| 60 | else: |
| 61 | from django.conf import settings |
| 62 | try: |
| 63 | sid = settings.SITE_ID |
| 64 | except AttributeError: |
| 65 | raise ImproperlyConfigured( |
| 66 | "You're using the Django \"sites framework\" without having " |
| 67 | "set the SITE_ID setting. Create a site in your database and " |
| 68 | "set the SITE_ID setting to fix this error.") |
| 69 | return self._get_site_by_id(sid) |
57 | 70 | |
58 | 71 | def clear_cache(self): |
59 | 72 | """Clears the ``Site`` object cache.""" |
diff --git a/django/contrib/sites/shortcuts.py b/django/contrib/sites/shortcuts.py
index c525948..ddff468 100644
a
|
b
|
def get_current_site(request):
|
12 | 12 | # the Site models when django.contrib.sites isn't installed. |
13 | 13 | if apps.is_installed('django.contrib.sites'): |
14 | 14 | from .models import Site |
15 | | return Site.objects.get_current() |
| 15 | from django.conf import settings |
| 16 | req = None if hasattr(settings, 'SITE_ID') else request |
| 17 | return Site.objects.get_current(req) |
16 | 18 | else: |
17 | 19 | from .requests import RequestSite |
18 | 20 | return RequestSite(request) |
diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py
index fadd4aa..7652c50 100644
a
|
b
|
class SitesFrameworkTests(TestCase):
|
71 | 71 | self.assertIsInstance(site, RequestSite) |
72 | 72 | self.assertEqual(site.name, "example.com") |
73 | 73 | |
| 74 | @override_settings(SITE_ID='', ALLOWED_HOSTS=['example.com']) |
| 75 | def test_get_current_site_no_site_id(self): |
| 76 | request = HttpRequest() |
| 77 | request.META = { |
| 78 | "SERVER_NAME": "example.com", |
| 79 | "SERVER_PORT": "80", |
| 80 | } |
| 81 | del settings.SITE_ID |
| 82 | site = get_current_site(request) |
| 83 | self.assertEqual(site.name, "example.com") |
| 84 | |
74 | 85 | def test_domain_name_with_whitespaces(self): |
75 | 86 | # Regression for #17320 |
76 | 87 | # Domain names are not allowed contain whitespace characters |
diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt
index 7561d54..0cb7edf 100644
a
|
b
|
The sites framework is mainly based on a simple model:
|
18 | 18 | .. class:: models.Site |
19 | 19 | |
20 | 20 | A model for storing the ``domain`` and ``name`` attributes of a Web site. |
21 | | The :setting:`SITE_ID` setting specifies the database ID of the |
22 | | :class:`~django.contrib.sites.models.Site` object (accessible using |
23 | | the automatically added ``id`` attribute) associated with that |
24 | | particular settings file. |
25 | 21 | |
26 | 22 | .. attribute:: domain |
27 | 23 | |
… |
… |
The sites framework is mainly based on a simple model:
|
31 | 27 | |
32 | 28 | A human-readable "verbose" name for the Web site. |
33 | 29 | |
| 30 | The :setting:`SITE_ID` setting specifies the database ID of the |
| 31 | :class:`~django.contrib.sites.models.Site` object associated with that |
| 32 | particular settings file. It is possible to omit it, but then the |
| 33 | :func:`~django.contrib.sites.shortcuts.get_current_site` function will always |
| 34 | try to get the current site by comparing the |
| 35 | :attr:`~django.contrib.sites.models.Site.domain` with the host name from |
| 36 | the :meth:`~django.http.HttpRequest.get_host` method. |
| 37 | |
34 | 38 | How you use this is up to you, but Django uses it in a couple of ways |
35 | 39 | automatically via simple conventions. |
36 | 40 | |
… |
… |
model(s). It's a model :doc:`manager </topics/db/managers>` that
|
308 | 312 | automatically filters its queries to include only objects associated |
309 | 313 | with the current :class:`~django.contrib.sites.models.Site`. |
310 | 314 | |
| 315 | .. admonition:: Mandatory SITE_ID |
| 316 | |
| 317 | The ``CurrentSiteManager`` is only usable when the :setting:`SITE_ID` |
| 318 | setting is defined in your settings. |
| 319 | |
311 | 320 | Use :class:`~django.contrib.sites.managers.CurrentSiteManager` by adding it to |
312 | 321 | your model explicitly. For example:: |
313 | 322 | |