Fixed #16734 -- Set script prefix even outside of requests

Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2015-10-23 21:02:34 +02:00
parent 9dcfecb7c6
commit 7d81ee6efc
8 changed files with 64 additions and 5 deletions

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
from django.utils.version import get_version from django.utils.version import get_version
VERSION = (1, 10, 0, 'alpha', 0) VERSION = (1, 10, 0, 'alpha', 0)
@ -5,14 +7,21 @@ VERSION = (1, 10, 0, 'alpha', 0)
__version__ = get_version(VERSION) __version__ = get_version(VERSION)
def setup(): def setup(set_prefix=True):
""" """
Configure the settings (this happens as a side effect of accessing the Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry. first setting), configure logging and populate the app registry.
Set the thread-local urlresolvers script prefix if `set_prefix` is True.
""" """
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import set_script_prefix
from django.utils.encoding import force_text
from django.utils.log import configure_logging from django.utils.log import configure_logging
configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
if set_prefix:
set_script_prefix(
'/' if settings.FORCE_SCRIPT_NAME is None else force_text(settings.FORCE_SCRIPT_NAME)
)
apps.populate(settings.INSTALLED_APPS) apps.populate(settings.INSTALLED_APPS)

View File

@ -10,5 +10,5 @@ def get_wsgi_application():
Allows us to avoid making django.core.handlers.WSGIHandler public API, in Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future. case the internal WSGI implementation changes or moves in the future.
""" """
django.setup() django.setup(set_prefix=False)
return WSGIHandler() return WSGIHandler()

View File

@ -332,14 +332,20 @@ application registry.
.. currentmodule:: django .. currentmodule:: django
.. function:: setup() .. function:: setup(set_script=True)
Configures Django by: Configures Django by:
* Loading the settings. * Loading the settings.
* Setting up logging. * Setting up logging.
* If ``set_script`` is True, setting the URL resolver script prefix to
:setting:`FORCE_SCRIPT_NAME` if defined, or ``/`` otherwise.
* Initializing the application registry. * Initializing the application registry.
.. versionchanged:: 1.10
The ability to set the URL resolver script prefix is new.
This function is called automatically: This function is called automatically:
* When running an HTTP server via Django's WSGI support. * When running an HTTP server via Django's WSGI support.

View File

@ -1408,7 +1408,14 @@ Default: ``None``
If not ``None``, this will be used as the value of the ``SCRIPT_NAME`` If not ``None``, this will be used as the value of the ``SCRIPT_NAME``
environment variable in any HTTP request. This setting can be used to override environment variable in any HTTP request. This setting can be used to override
the server-provided value of ``SCRIPT_NAME``, which may be a rewritten version the server-provided value of ``SCRIPT_NAME``, which may be a rewritten version
of the preferred value or not supplied at all. of the preferred value or not supplied at all. It is also used by
:func:`django.setup()` to set the URL resolver script prefix outside of the
request/response cycle (e.g. in management commands and standalone scripts) to
generate correct URLs when ``SCRIPT_NAME`` is not ``/``.
.. versionchanged:: 1.10
The setting's use in :func:`django.setup()` was added.
.. setting:: FORMAT_MODULE_PATH .. setting:: FORMAT_MODULE_PATH

View File

@ -209,7 +209,10 @@ Tests
URLs URLs
^^^^ ^^^^
* ... * An addition in :func:`django.setup()` allows URL resolving that happens
outside of the request/response cycle (e.g. in management commands and
standalone scripts) to take :setting:`FORCE_SCRIPT_NAME` into account when it
is set.
Validators Validators
^^^^^^^^^^ ^^^^^^^^^^

View File

@ -0,0 +1,10 @@
from django.core.management.base import BaseCommand
from django.core.urlresolvers import reverse
class Command(BaseCommand):
"""
This command returns a URL from a reverse() call.
"""
def handle(self, *args, **options):
return reverse('some_url')

View File

@ -1,5 +1,7 @@
import os import os
from admin_scripts.tests import AdminScriptTestCase
from django.apps import apps from django.apps import apps
from django.core import management from django.core import management
from django.core.management import BaseCommand, CommandError, find_commands from django.core.management import BaseCommand, CommandError, find_commands
@ -159,6 +161,23 @@ class CommandTests(SimpleTestCase):
BaseCommand.check = saved_check BaseCommand.check = saved_check
class CommandRunTests(AdminScriptTestCase):
"""
Tests that need to run by simulating the command line, not by call_command.
"""
def tearDown(self):
self.remove_settings('settings.py')
def test_script_prefix_set_in_commands(self):
self.write_settings('settings.py', apps=['user_commands'], sdict={
'ROOT_URLCONF': '"user_commands.urls"',
'FORCE_SCRIPT_NAME': '"/PREFIX/"',
})
out, err = self.run_manage(['reverse_url'])
self.assertNoOutput(err)
self.assertEqual(out.strip(), '/PREFIX/some/url/')
class UtilsTests(SimpleTestCase): class UtilsTests(SimpleTestCase):
def test_no_existent_external_program(self): def test_no_existent_external_program(self):

View File

@ -0,0 +1,5 @@
from django.conf.urls import url
urlpatterns = [
url(r'^some/url/$', lambda req:req, name='some_url'),
]