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
VERSION = (1, 10, 0, 'alpha', 0)
@ -5,14 +7,21 @@ VERSION = (1, 10, 0, 'alpha', 0)
__version__ = get_version(VERSION)
def setup():
def setup(set_prefix=True):
"""
Configure the settings (this happens as a side effect of accessing the
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.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
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)

View File

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

View File

@ -332,14 +332,20 @@ application registry.
.. currentmodule:: django
.. function:: setup()
.. function:: setup(set_script=True)
Configures Django by:
* Loading the settings.
* 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.
.. versionchanged:: 1.10
The ability to set the URL resolver script prefix is new.
This function is called automatically:
* 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``
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
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

View File

@ -209,7 +209,10 @@ Tests
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
^^^^^^^^^^

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
from admin_scripts.tests import AdminScriptTestCase
from django.apps import apps
from django.core import management
from django.core.management import BaseCommand, CommandError, find_commands
@ -159,6 +161,23 @@ class CommandTests(SimpleTestCase):
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):
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'),
]