Moved RequestSite and get_current_site.
Following the app-loading refactor, these objects must live outside of django.contrib.sites.models because they must be available without importing the django.contrib.sites.models module when django.contrib.sites isn't installed. Refs #21680. Thanks Carl and Loic for reporting this issue.
This commit is contained in:
parent
ca95f8e435
commit
9ffab9cee1
|
@ -16,7 +16,7 @@ from django.contrib.auth import authenticate, get_user_model
|
|||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX, identify_hasher
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
|
||||
UNMASKED_DIGITS_TO_SHOW = 6
|
||||
|
|
|
@ -4,7 +4,8 @@ import os
|
|||
import re
|
||||
|
||||
from django.conf import global_settings, settings
|
||||
from django.contrib.sites.models import Site, RequestSite
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.requests import RequestSite
|
||||
from django.contrib.admin.models import LogEntry
|
||||
from django.contrib.auth.models import User
|
||||
from django.core import mail
|
||||
|
|
|
@ -15,7 +15,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login, logout
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, PasswordChangeForm
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
|
||||
@sensitive_post_parameters()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from django.contrib.syndication.views import Feed
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.contrib import comments
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ from django.contrib.comments import signals
|
|||
from django.db.models.base import ModelBase
|
||||
from django.template import Context, loader
|
||||
from django.contrib import comments
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.utils import timezone
|
||||
|
||||
class AlreadyModerated(Exception):
|
||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes.views import shortcut
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.db import models
|
||||
from django.http import HttpRequest, Http404
|
||||
from django.test import TestCase, override_settings
|
||||
|
|
|
@ -2,7 +2,8 @@ from __future__ import unicode_literals
|
|||
|
||||
from django import http
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.sites.models import Site, get_current_site
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template import loader, RequestContext
|
||||
|
|
|
@ -5,7 +5,7 @@ import warnings
|
|||
from django.apps import apps
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.template import loader
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core import urlresolvers
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||
from django.contrib.gis.db.models.fields import GeometryField
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib.redirects.models import Redirect
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django import http
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from calendar import timegm
|
||||
from functools import wraps
|
||||
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core import urlresolvers
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||
from django.http import Http404
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import string
|
||||
import warnings
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
||||
from django.db import models
|
||||
|
@ -8,6 +9,9 @@ from django.db.models.signals import pre_save, pre_delete
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
from .requests import RequestSite as RealRequestSite
|
||||
from .shortcuts import get_current_site as real_get_current_site
|
||||
|
||||
|
||||
SITE_CACHE = {}
|
||||
|
||||
|
@ -74,38 +78,19 @@ class Site(models.Model):
|
|||
return self.domain
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class RequestSite(object):
|
||||
"""
|
||||
A class that shares the primary interface of Site (i.e., it has
|
||||
``domain`` and ``name`` attributes) but gets its data from a Django
|
||||
HttpRequest object rather than from a database.
|
||||
|
||||
The save() and delete() methods raise NotImplementedError.
|
||||
"""
|
||||
def __init__(self, request):
|
||||
self.domain = self.name = request.get_host()
|
||||
|
||||
def __str__(self):
|
||||
return self.domain
|
||||
|
||||
def save(self, force_insert=False, force_update=False):
|
||||
raise NotImplementedError('RequestSite cannot be saved.')
|
||||
|
||||
def delete(self):
|
||||
raise NotImplementedError('RequestSite cannot be deleted.')
|
||||
class RequestSite(RealRequestSite):
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn(
|
||||
"Please import RequestSite from django.contrib.sites.requests.",
|
||||
PendingDeprecationWarning, stacklevel=2)
|
||||
super(RequestSite, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def get_current_site(request):
|
||||
"""
|
||||
Checks if contrib.sites is installed and returns either the current
|
||||
``Site`` object or a ``RequestSite`` object based on the request.
|
||||
"""
|
||||
if Site._meta.installed:
|
||||
current_site = Site.objects.get_current()
|
||||
else:
|
||||
current_site = RequestSite(request)
|
||||
return current_site
|
||||
warnings.warn(
|
||||
"Please import get_current_site from django.contrib.sites.shortcuts.",
|
||||
PendingDeprecationWarning, stacklevel=2)
|
||||
return real_get_current_site(request)
|
||||
|
||||
|
||||
def clear_site_cache(sender, **kwargs):
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class RequestSite(object):
|
||||
"""
|
||||
A class that shares the primary interface of Site (i.e., it has
|
||||
``domain`` and ``name`` attributes) but gets its data from a Django
|
||||
HttpRequest object rather than from a database.
|
||||
|
||||
The save() and delete() methods raise NotImplementedError.
|
||||
"""
|
||||
def __init__(self, request):
|
||||
self.domain = self.name = request.get_host()
|
||||
|
||||
def __str__(self):
|
||||
return self.domain
|
||||
|
||||
def save(self, force_insert=False, force_update=False):
|
||||
raise NotImplementedError('RequestSite cannot be saved.')
|
||||
|
||||
def delete(self):
|
||||
raise NotImplementedError('RequestSite cannot be deleted.')
|
|
@ -0,0 +1,18 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import apps
|
||||
|
||||
|
||||
def get_current_site(request):
|
||||
"""
|
||||
Checks if contrib.sites is installed and returns either the current
|
||||
``Site`` object or a ``RequestSite`` object based on the request.
|
||||
"""
|
||||
# Imports are inside the function because its point is to avoid importing
|
||||
# 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()
|
||||
else:
|
||||
from .requests import RequestSite
|
||||
return RequestSite(request)
|
|
@ -1,11 +1,14 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site, RequestSite, get_current_site
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||
from django.http import HttpRequest
|
||||
from django.test import TestCase, modify_settings, override_settings
|
||||
|
||||
from .models import Site
|
||||
from .requests import RequestSite
|
||||
from .shortcuts import get_current_site
|
||||
|
||||
|
||||
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
|
||||
class SitesFrameworkTests(TestCase):
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||
from calendar import timegm
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.template import loader, TemplateDoesNotExist, RequestContext
|
||||
|
|
|
@ -12,7 +12,7 @@ def cache_page(*args, **kwargs):
|
|||
The cache is keyed by the URL and some data from the headers.
|
||||
Additionally there is the key prefix that is used to distinguish different
|
||||
cache areas in a multi-site setup. You could use the
|
||||
sites.get_current_site().domain, for example, as that is unique across a Django
|
||||
get_current_site().domain, for example, as that is unique across a Django
|
||||
project.
|
||||
|
||||
Additionally, all headers from the response's Vary header will be taken
|
||||
|
|
|
@ -184,6 +184,9 @@ these changes.
|
|||
|
||||
* ``AppCommand.handle_app()`` will no longer be supported.
|
||||
|
||||
* ``RequestSite`` will be located in ``django.contrib.sites.requests`` and
|
||||
``get_current_site`` in ``django.contrib.sites.shortcuts``.
|
||||
|
||||
* FastCGI support via the ``runfcgi`` management command will be
|
||||
removed. Please deploy your project using WSGI.
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ The "sites" framework
|
|||
:synopsis: Lets you operate multiple Web sites from the same database and
|
||||
Django project
|
||||
|
||||
.. currentmodule:: django.contrib.sites.models
|
||||
|
||||
Django comes with an optional "sites" framework. It's a hook for associating
|
||||
objects and functionality to particular Web sites, and it's a holding place for
|
||||
the domain names and "verbose" names of your Django-powered sites.
|
||||
|
@ -15,9 +13,9 @@ the domain names and "verbose" names of your Django-powered sites.
|
|||
Use it if your single Django installation powers more than one site and you
|
||||
need to differentiate between those sites in some way.
|
||||
|
||||
The whole sites framework is based on a simple model:
|
||||
The sites framework is mainly based on a simple model:
|
||||
|
||||
.. class:: Site
|
||||
.. class:: models.Site
|
||||
|
||||
A model for storing the ``domain`` and ``name`` attributes of a Web site.
|
||||
The :setting:`SITE_ID` setting specifies the database ID of the
|
||||
|
@ -32,7 +30,6 @@ The whole sites framework is based on a simple model:
|
|||
|
||||
A human-readable "verbose" name for the Web site.
|
||||
|
||||
|
||||
How you use this is up to you, but Django uses it in a couple of ways
|
||||
automatically via simple conventions.
|
||||
|
||||
|
@ -80,7 +77,7 @@ This accomplishes several things quite nicely:
|
|||
The view code that displays a given story just checks to make sure the
|
||||
requested story is on the current site. It looks something like this::
|
||||
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
def article_detail(request, article_id):
|
||||
try:
|
||||
|
@ -137,7 +134,7 @@ hard-coding is best for hackish fixes that you need done quickly. The
|
|||
cleaner way of accomplishing the same thing is to check the current site's
|
||||
domain::
|
||||
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
def my_view(request):
|
||||
current_site = get_current_site(request)
|
||||
|
@ -149,7 +146,8 @@ domain::
|
|||
pass
|
||||
|
||||
This has also the advantage of checking if the sites framework is installed,
|
||||
and return a :class:`RequestSite` instance if it is not.
|
||||
and return a :class:`~django.contrib.sites.requests.RequestSite` instance if
|
||||
it is not.
|
||||
|
||||
If you don't have access to the request object, you can use the
|
||||
``get_current()`` method of the :class:`~django.contrib.sites.models.Site`
|
||||
|
@ -185,7 +183,7 @@ current site's :attr:`~django.contrib.sites.models.Site.name` and
|
|||
|
||||
Here's an example of what the form-handling view looks like::
|
||||
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.mail import send_mail
|
||||
|
||||
def register_for_newsletter(request):
|
||||
|
@ -296,12 +294,10 @@ clear the cache using ``Site.objects.clear_cache()``::
|
|||
Site.objects.clear_cache()
|
||||
current_site = Site.objects.get_current()
|
||||
|
||||
.. currentmodule:: django.contrib.sites.managers
|
||||
|
||||
The ``CurrentSiteManager``
|
||||
==========================
|
||||
|
||||
.. class:: CurrentSiteManager
|
||||
.. class:: managers.CurrentSiteManager
|
||||
|
||||
If :class:`~django.contrib.sites.models.Site` plays a key role in your
|
||||
application, consider using the helpful
|
||||
|
@ -426,8 +422,6 @@ Here's how Django uses the sites framework:
|
|||
:class:`~django.contrib.sites.models.Site` to work out the domain for the
|
||||
site that it will redirect to.
|
||||
|
||||
.. currentmodule:: django.contrib.sites.models
|
||||
|
||||
``RequestSite`` objects
|
||||
=======================
|
||||
|
||||
|
@ -435,32 +429,50 @@ Here's how Django uses the sites framework:
|
|||
|
||||
Some :doc:`django.contrib </ref/contrib/index>` applications take advantage of
|
||||
the sites framework but are architected in a way that doesn't *require* the
|
||||
sites framework to be installed in your database. (Some people don't want to, or
|
||||
just aren't *able* to install the extra database table that the sites framework
|
||||
requires.) For those cases, the framework provides a
|
||||
:class:`~django.contrib.sites.models.RequestSite` class, which can be used as a
|
||||
fallback when the database-backed sites framework is not available.
|
||||
sites framework to be installed in your database. (Some people don't want to,
|
||||
or just aren't *able* to install the extra database table that the sites
|
||||
framework requires.) For those cases, the framework provides a
|
||||
:class:`django.contrib.sites.requests.RequestSite` class, which can be used as
|
||||
a fallback when the database-backed sites framework is not available.
|
||||
|
||||
.. class:: RequestSite
|
||||
.. class:: requests.RequestSite
|
||||
|
||||
A class that shares the primary interface of
|
||||
:class:`~django.contrib.sites.models.Site` (i.e., it has
|
||||
``domain`` and ``name`` attributes) but gets its data from a Django
|
||||
:class:`~django.http.HttpRequest` object rather than from a database.
|
||||
|
||||
The ``save()`` and ``delete()`` methods raise ``NotImplementedError``.
|
||||
|
||||
.. method:: __init__(request)
|
||||
|
||||
Sets the ``name`` and ``domain`` attributes to the value of
|
||||
:meth:`~django.http.HttpRequest.get_host`.
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
A :class:`~django.contrib.sites.models.RequestSite` object has a similar
|
||||
interface to a normal :class:`~django.contrib.sites.models.Site` object, except
|
||||
its :meth:`~django.contrib.sites.models.RequestSite.__init__()` method takes an
|
||||
:class:`~django.http.HttpRequest` object. It's able to deduce the
|
||||
``domain`` and ``name`` by looking at the request's domain. It has ``save()``
|
||||
and ``delete()`` methods to match the interface of
|
||||
This class used to be defined in ``django.contrib.sites.models``.
|
||||
|
||||
A :class:`~django.contrib.sites.requests.RequestSite` object has a similar
|
||||
interface to a normal :class:`~django.contrib.sites.models.Site` object,
|
||||
except its :meth:`~django.contrib.sites.requests.RequestSite.__init__()`
|
||||
method takes an :class:`~django.http.HttpRequest` object. It's able to deduce
|
||||
the ``domain`` and ``name`` by looking at the request's domain. It has
|
||||
``save()`` and ``delete()`` methods to match the interface of
|
||||
:class:`~django.contrib.sites.models.Site`, but the methods raise
|
||||
``NotImplementedError``.
|
||||
:exc:`~exceptions.NotImplementedError`..
|
||||
|
||||
``get_current_site`` shortcut
|
||||
=============================
|
||||
|
||||
Finally, to avoid repetitive fallback code, the framework provides a
|
||||
:func:`django.contrib.sites.shortcut.get_current_site` function.
|
||||
|
||||
.. function:: shortcuts.get_current_site
|
||||
|
||||
A function that checks if ``django.contrib.sites`` is installed and
|
||||
returns either the current :class:`~django.contrib.sites.models.Site`
|
||||
object or a :class:`~django.contrib.sites.requests.RequestSite` object
|
||||
based on the request.
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
This function used to be defined in ``django.contrib.sites.models``.
|
||||
|
|
|
@ -131,7 +131,7 @@ into those elements.
|
|||
representing the current site. This is useful for ``{{ site.domain
|
||||
}}`` or ``{{ site.name }}``. If you do *not* have the Django sites
|
||||
framework installed, this will be set to a
|
||||
:class:`django.contrib.sites.models.RequestSite` object. See the
|
||||
:class:`~django.contrib.sites.requests.RequestSite` object. See the
|
||||
:ref:`RequestSite section of the sites framework documentation
|
||||
<requestsite-objects>` for more.
|
||||
|
||||
|
|
|
@ -1009,6 +1009,19 @@ than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data
|
|||
will search ``myapp/sql/`` as documented. The old location will continue to
|
||||
work until Django 1.9.
|
||||
|
||||
Reorganization of ``django.contrib.sites``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``django.contrib.sites`` provides reduced functionality when it isn't in
|
||||
:setting:`INSTALLED_APPS`. The app-loading refactor adds some constraints in
|
||||
that situation. As a consequence, two objects were moved, and the old
|
||||
locations are deprecated:
|
||||
|
||||
* :class:`~django.contrib.sites.requests.RequestSite` now lives in
|
||||
``django.contrib.sites.requests``.
|
||||
* :func:`~django.contrib.sites.shortcuts.get_current_site` now lives in
|
||||
``django.contrib.sites.shortcuts``.
|
||||
|
||||
``declared_fieldsets`` attribute on ``ModelAdmin``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -648,7 +648,7 @@ patterns.
|
|||
* ``site``: The current :class:`~django.contrib.sites.models.Site`,
|
||||
according to the :setting:`SITE_ID` setting. If you don't have the
|
||||
site framework installed, this will be set to an instance of
|
||||
:class:`~django.contrib.sites.models.RequestSite`, which derives the
|
||||
:class:`~django.contrib.sites.requests.RequestSite`, which derives the
|
||||
site name and domain from the current
|
||||
:class:`~django.http.HttpRequest`.
|
||||
|
||||
|
@ -744,7 +744,7 @@ patterns.
|
|||
* ``site``: The current :class:`~django.contrib.sites.models.Site`,
|
||||
according to the :setting:`SITE_ID` setting. If you don't have the
|
||||
site framework installed, this will be set to an instance of
|
||||
:class:`~django.contrib.sites.models.RequestSite`, which derives the
|
||||
:class:`~django.contrib.sites.requests.RequestSite`, which derives the
|
||||
site name and domain from the current
|
||||
:class:`~django.http.HttpRequest`.
|
||||
|
||||
|
|
Loading…
Reference in New Issue