mirror of https://github.com/django/django.git
Fixed #6218 -- Made MEDIA_URL and STATIC_URL require a trailing slash to ensure there is a consistent way to combine paths in templates. Thanks to Michael Toomim, Chris Heisel and Chris Beaven.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15130 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
7a89d3d503
commit
544ab30ed7
|
@ -9,6 +9,7 @@ a list of all possible variables.
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time # Needed for Windows
|
import time # Needed for Windows
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.conf import global_settings
|
from django.conf import global_settings
|
||||||
from django.utils.functional import LazyObject
|
from django.utils.functional import LazyObject
|
||||||
|
@ -60,7 +61,19 @@ class LazySettings(LazyObject):
|
||||||
return bool(self._wrapped)
|
return bool(self._wrapped)
|
||||||
configured = property(configured)
|
configured = property(configured)
|
||||||
|
|
||||||
class Settings(object):
|
|
||||||
|
class BaseSettings(object):
|
||||||
|
"""
|
||||||
|
Common logic for settings whether set by a module or by the user.
|
||||||
|
"""
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if name in ("MEDIA_URL", "STATIC_URL") and value and not value.endswith('/'):
|
||||||
|
warnings.warn('If set, %s must end with a slash' % name,
|
||||||
|
PendingDeprecationWarning)
|
||||||
|
object.__setattr__(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
def __init__(self, settings_module):
|
def __init__(self, settings_module):
|
||||||
# update this dict from global settings (but only for ALL_CAPS settings)
|
# update this dict from global settings (but only for ALL_CAPS settings)
|
||||||
for setting in dir(global_settings):
|
for setting in dir(global_settings):
|
||||||
|
@ -125,7 +138,8 @@ class Settings(object):
|
||||||
# ... then invoke it with the logging settings
|
# ... then invoke it with the logging settings
|
||||||
logging_config_func(self.LOGGING)
|
logging_config_func(self.LOGGING)
|
||||||
|
|
||||||
class UserSettingsHolder(object):
|
|
||||||
|
class UserSettingsHolder(BaseSettings):
|
||||||
"""
|
"""
|
||||||
Holder for user configured settings.
|
Holder for user configured settings.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -48,7 +48,7 @@ USE_L10N = True
|
||||||
MEDIA_ROOT = ''
|
MEDIA_ROOT = ''
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
# trailing slash.
|
||||||
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
||||||
MEDIA_URL = ''
|
MEDIA_URL = ''
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,10 @@ their deprecation, as per the :ref:`Django deprecation policy
|
||||||
* Authentication backends need to define the boolean attribute
|
* Authentication backends need to define the boolean attribute
|
||||||
``supports_inactive_user``.
|
``supports_inactive_user``.
|
||||||
|
|
||||||
|
* The ``MEDIA_URL`` or ``STATIC_URL`` settings are required to end
|
||||||
|
with a trailing slash to ensure there is a consistent way to
|
||||||
|
combine paths in templates.
|
||||||
|
|
||||||
* 1.5
|
* 1.5
|
||||||
* The ``mod_python`` request handler has been deprecated since the 1.3
|
* The ``mod_python`` request handler has been deprecated since the 1.3
|
||||||
release. The ``mod_wsgi`` handler should be used instead.
|
release. The ``mod_wsgi`` handler should be used instead.
|
||||||
|
|
|
@ -1251,10 +1251,8 @@ for :doc:`managing stored files </topics/files>`.
|
||||||
|
|
||||||
Example: ``"http://media.lawrence.com/"``
|
Example: ``"http://media.lawrence.com/"``
|
||||||
|
|
||||||
Note that this should have a trailing slash if it has a path component.
|
.. versionchanged:: 1.3
|
||||||
|
It must end in a slash if set to a non-empty value.
|
||||||
* Good: ``"http://www.example.com/media/"``
|
|
||||||
* Bad: ``"http://www.example.com/media"``
|
|
||||||
|
|
||||||
MESSAGE_LEVEL
|
MESSAGE_LEVEL
|
||||||
-------------
|
-------------
|
||||||
|
@ -1664,6 +1662,8 @@ If not ``None``, this will be used as the base path for
|
||||||
:ref:`media definitions<form-media-paths>` and the
|
:ref:`media definitions<form-media-paths>` and the
|
||||||
:doc:`staticfiles app</ref/contrib/staticfiles>`.
|
:doc:`staticfiles app</ref/contrib/staticfiles>`.
|
||||||
|
|
||||||
|
It must end in a slash if set to a non-empty value.
|
||||||
|
|
||||||
See :setting:`STATIC_ROOT`.
|
See :setting:`STATIC_ROOT`.
|
||||||
|
|
||||||
.. setting:: TEMPLATE_CONTEXT_PROCESSORS
|
.. setting:: TEMPLATE_CONTEXT_PROCESSORS
|
||||||
|
|
|
@ -192,6 +192,22 @@ The GeoDjango test suite is now included when
|
||||||
:ref:`running the Django test suite <running-unit-tests>` with ``runtests.py``
|
:ref:`running the Django test suite <running-unit-tests>` with ``runtests.py``
|
||||||
when using :ref:`spatial database backends <spatial-backends>`.
|
when using :ref:`spatial database backends <spatial-backends>`.
|
||||||
|
|
||||||
|
``MEDIA_URL`` and ``STATIC_URL`` must end in a slash
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
Previously, the ``MEDIA_URL`` setting only required a trailing slash if it
|
||||||
|
contained a suffix beyond the domain name.
|
||||||
|
|
||||||
|
A trailing slash is now *required* for ``MEDIA_URL`` and the new
|
||||||
|
``STATIC_URL`` setting as long as it is not blank. This ensures there is
|
||||||
|
a consistent way to combine paths in templates.
|
||||||
|
|
||||||
|
Project settings which provide either of both settings without a trailing
|
||||||
|
slash will now raise a ``PendingDeprecation`` warning.
|
||||||
|
|
||||||
|
In Django 1.4 this same condition will raise an ``ImproperlyConfigured``
|
||||||
|
exception.
|
||||||
|
|
||||||
Everything else
|
Everything else
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
|
from django.conf import settings, UserSettingsHolder, global_settings
|
||||||
|
|
||||||
|
|
||||||
class SettingsTests(unittest.TestCase):
|
class SettingsTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -15,3 +17,62 @@ class SettingsTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_settings_delete_wrapped(self):
|
def test_settings_delete_wrapped(self):
|
||||||
self.assertRaises(TypeError, delattr, settings, '_wrapped')
|
self.assertRaises(TypeError, delattr, settings, '_wrapped')
|
||||||
|
|
||||||
|
|
||||||
|
class TrailingSlashURLTests(unittest.TestCase):
|
||||||
|
settings_module = settings
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self._original_media_url = self.settings_module.MEDIA_URL
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.settings_module.MEDIA_URL = self._original_media_url
|
||||||
|
|
||||||
|
def test_blank(self):
|
||||||
|
"""
|
||||||
|
If blank, no PendingDeprecationWarning error will be raised, even though it
|
||||||
|
doesn't end in a slash.
|
||||||
|
"""
|
||||||
|
self.settings_module.MEDIA_URL = ''
|
||||||
|
self.assertEqual('', self.settings_module.MEDIA_URL)
|
||||||
|
|
||||||
|
def test_end_slash(self):
|
||||||
|
"""
|
||||||
|
MEDIA_URL works if you end in a slash.
|
||||||
|
"""
|
||||||
|
self.settings_module.MEDIA_URL = '/foo/'
|
||||||
|
self.assertEqual('/foo/', self.settings_module.MEDIA_URL)
|
||||||
|
|
||||||
|
self.settings_module.MEDIA_URL = 'http://media.foo.com/'
|
||||||
|
self.assertEqual('http://media.foo.com/',
|
||||||
|
self.settings_module.MEDIA_URL)
|
||||||
|
|
||||||
|
def test_no_end_slash(self):
|
||||||
|
"""
|
||||||
|
MEDIA_URL raises an PendingDeprecationWarning error if it doesn't end in a
|
||||||
|
slash.
|
||||||
|
"""
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('error', 'If set, MEDIA_URL must end with a slash', PendingDeprecationWarning)
|
||||||
|
|
||||||
|
def setattr_settings(settings_module, attr, value):
|
||||||
|
setattr(settings_module, attr, value)
|
||||||
|
|
||||||
|
self.assertRaises(PendingDeprecationWarning, setattr_settings,
|
||||||
|
self.settings_module, 'MEDIA_URL', '/foo')
|
||||||
|
|
||||||
|
self.assertRaises(PendingDeprecationWarning, setattr_settings,
|
||||||
|
self.settings_module, 'MEDIA_URL',
|
||||||
|
'http://media.foo.com')
|
||||||
|
|
||||||
|
def test_double_slash(self):
|
||||||
|
"""
|
||||||
|
If a MEDIA_URL ends in more than one slash, presume they know what
|
||||||
|
they're doing.
|
||||||
|
"""
|
||||||
|
self.settings_module.MEDIA_URL = '/stupid//'
|
||||||
|
self.assertEqual('/stupid//', self.settings_module.MEDIA_URL)
|
||||||
|
|
||||||
|
self.settings_module.MEDIA_URL = 'http://media.foo.com/stupid//'
|
||||||
|
self.assertEqual('http://media.foo.com/stupid//',
|
||||||
|
self.settings_module.MEDIA_URL)
|
||||||
|
|
Loading…
Reference in New Issue