summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/utils/formats.py13
-rw-r--r--docs/ref/settings.txt14
-rw-r--r--docs/releases/1.8.txt5
-rw-r--r--docs/topics/i18n/formatting.txt17
-rw-r--r--tests/utils_tests/test_formats.py59
-rw-r--r--tests/utils_tests/test_module/formats/__init__.py4
-rw-r--r--tests/utils_tests/test_module/formats/en/__init__.py0
-rw-r--r--tests/utils_tests/test_module/formats/en/formats.py0
-rw-r--r--tests/utils_tests/test_module/formats2/__init__.py0
-rw-r--r--tests/utils_tests/test_module/formats2/en/__init__.py0
-rw-r--r--tests/utils_tests/test_module/formats2/en/formats.py0
11 files changed, 103 insertions, 9 deletions
diff --git a/django/utils/formats.py b/django/utils/formats.py
index fc68179f3a..5bb8d75df7 100644
--- a/django/utils/formats.py
+++ b/django/utils/formats.py
@@ -47,10 +47,15 @@ def iter_format_modules(lang, format_module_path=None):
Does the heavy lifting of finding format modules.
"""
if check_for_language(lang):
- format_locations = ['django.conf.locale.%s']
- if format_module_path:
- format_locations.append(format_module_path + '.%s')
- format_locations.reverse()
+ format_locations = []
+ if settings.FORMAT_MODULE_PATH:
+ if isinstance(settings.FORMAT_MODULE_PATH, six.string_types):
+ format_module_path_setting = [settings.FORMAT_MODULE_PATH]
+ else:
+ format_module_path_setting = settings.FORMAT_MODULE_PATH
+ for path in format_module_path_setting:
+ format_locations.append(path + '.%s')
+ format_locations.append('django.conf.locale.%s')
locale = to_locale(lang)
locales = [locale]
if '_' in locale:
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 597e39ab99..926f0d300e 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -1378,6 +1378,20 @@ like::
__init__.py
formats.py
+.. versionchanged:: 1.8
+
+ You can also set this setting to a list of Python paths, for example::
+
+ FORMAT_MODULE_PATH = [
+ 'mysite.formats',
+ 'some_app.formats',
+ ]
+
+ When Django searches for a certain format, it will go through all given
+ Python paths until it finds a module that actually defines the given
+ format. This means that formats defined in packages farther up in the list
+ will take precedence over the same formats in packages farther down.
+
Available formats are :setting:`DATE_FORMAT`, :setting:`TIME_FORMAT`,
:setting:`DATETIME_FORMAT`, :setting:`YEAR_MONTH_FORMAT`,
:setting:`MONTH_DAY_FORMAT`, :setting:`SHORT_DATE_FORMAT`,
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index 6b0cb85058..22d8ca7d20 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -133,7 +133,10 @@ Forms
Internationalization
^^^^^^^^^^^^^^^^^^^^
-* ...
+* :setting:`FORMAT_MODULE_PATH` can now be a list of strings representing
+ module paths. This allows importing several format modules from different
+ reusable apps. It also allows overriding those custom formats in your main
+ Django project.
Management Commands
^^^^^^^^^^^^^^^^^^^
diff --git a/docs/topics/i18n/formatting.txt b/docs/topics/i18n/formatting.txt
index 04b36e2767..94b2eed8ee 100644
--- a/docs/topics/i18n/formatting.txt
+++ b/docs/topics/i18n/formatting.txt
@@ -154,11 +154,20 @@ Django provides format definitions for many locales, but sometimes you might
want to create your own, because a format files doesn't exist for your locale,
or because you want to overwrite some of the values.
-To use custom formats, specify the path where you'll place format files first.
-To do that, just set your :setting:`FORMAT_MODULE_PATH` setting to the package
-where format files will exist, for instance::
- FORMAT_MODULE_PATH = 'mysite.formats'
+.. versionchanged:: 1.8
+
+ The ability to specify FORMAT_MODULE_PATH as a list was added. Previously,
+ only a single string value was supported.
+
+To use custom formats, specify the path where you'll place format files
+first. To do that, just set your :setting:`FORMAT_MODULE_PATH` setting to
+the package where format files will exist, for instance::
+
+ FORMAT_MODULE_PATH = [
+ 'mysite.formats',
+ 'some_app.formats',
+ ]
Files are not placed directly in this directory, but in a directory named as
the locale, and must be named ``formats.py``.
diff --git a/tests/utils_tests/test_formats.py b/tests/utils_tests/test_formats.py
new file mode 100644
index 0000000000..17fa9fdadf
--- /dev/null
+++ b/tests/utils_tests/test_formats.py
@@ -0,0 +1,59 @@
+"""Tests for ``django/utils/formats.py``."""
+from django.test import TestCase
+from django.utils.formats import iter_format_modules
+
+
+class IterFormatModulesTestCase(TestCase):
+ """Tests for the ``iter_format_modules`` method."""
+ longMessage = True
+
+ def test_returns_correct_default(self):
+ """
+ Should return default module when FORMAT_MODULE_PATH is not set.
+ """
+ result = list(iter_format_modules('en'))
+ self.assertEqual(len(result), 1, msg=(
+ "Should return only Django's default formats module."))
+ self.assertEqual(
+ result[0].__name__, 'django.conf.locale.en.formats', msg=(
+ 'Should have added the language to the module path'))
+
+ def test_with_setting_as_basestring(self):
+ """
+ Before ticket #20477 FORMAT_MODULE_PATH was supposed to be a string.
+
+ This test ensures backwards compatibility.
+ """
+ with self.settings(
+ FORMAT_MODULE_PATH='utils_tests.test_module.formats'):
+ result = list(iter_format_modules('en'))
+ self.assertEqual(len(result), 2, msg=(
+ 'Should return both, the default value and the one from the'
+ ' setting'))
+ self.assertEqual(
+ result[0].__name__,
+ 'utils_tests.test_module.formats.en.formats',
+ msg=('Should return the module from the setting first and'
+ ' should have added the language to the module path'))
+
+ def test_with_setting_as_list_of_strings(self):
+ """
+ After ticket #20477 FORMAT_MODULE_PATH can also be a list of strings.
+
+ This tests verifies the new functionality.
+ """
+ FORMAT_MODULE_PATH = [
+ 'utils_tests.test_module.formats',
+ 'utils_tests.test_module.formats2',
+ ]
+ with self.settings(
+ FORMAT_MODULE_PATH=FORMAT_MODULE_PATH):
+ result = list(iter_format_modules('en'))
+ self.assertEqual(len(result), 3, msg=(
+ 'Should return the default value and the two values from the'
+ ' setting'))
+ self.assertEqual(
+ result[0].__name__,
+ 'utils_tests.test_module.formats.en.formats',
+ msg=('Should return the values from the setting and add the'
+ ' language to the module path'))
diff --git a/tests/utils_tests/test_module/formats/__init__.py b/tests/utils_tests/test_module/formats/__init__.py
new file mode 100644
index 0000000000..6dc04db23d
--- /dev/null
+++ b/tests/utils_tests/test_module/formats/__init__.py
@@ -0,0 +1,4 @@
+"""
+Custom format module. Used by tests in ``tests/utils_tests/test_formats.py``.
+
+"""
diff --git a/tests/utils_tests/test_module/formats/en/__init__.py b/tests/utils_tests/test_module/formats/en/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/utils_tests/test_module/formats/en/__init__.py
diff --git a/tests/utils_tests/test_module/formats/en/formats.py b/tests/utils_tests/test_module/formats/en/formats.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/utils_tests/test_module/formats/en/formats.py
diff --git a/tests/utils_tests/test_module/formats2/__init__.py b/tests/utils_tests/test_module/formats2/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/utils_tests/test_module/formats2/__init__.py
diff --git a/tests/utils_tests/test_module/formats2/en/__init__.py b/tests/utils_tests/test_module/formats2/en/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/utils_tests/test_module/formats2/en/__init__.py
diff --git a/tests/utils_tests/test_module/formats2/en/formats.py b/tests/utils_tests/test_module/formats2/en/formats.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/utils_tests/test_module/formats2/en/formats.py