diff --git a/constance/admin.py b/constance/admin.py index 9bf8dbb2..b31d2503 100644 --- a/constance/admin.py +++ b/constance/admin.py @@ -19,6 +19,7 @@ from django.utils.encoding import smart_bytes from django.utils.formats import localize from django.utils.module_loading import import_string +from django.utils.text import normalize_newlines from django.utils.translation import ugettext_lazy as _ from . import LazyConfig, settings @@ -146,6 +147,9 @@ def save(self): current = getattr(config, name) new = self.cleaned_data[name] + if isinstance(new, str): + new = normalize_newlines(new) + if conf.settings.USE_TZ and isinstance(current, datetime) and not timezone.is_aware(current): current = timezone.make_aware(current) diff --git a/example/cheeseshop/settings.py b/example/cheeseshop/settings.py index ca03d995..6a88a856 100644 --- a/example/cheeseshop/settings.py +++ b/example/cheeseshop/settings.py @@ -111,6 +111,7 @@ 'MUSICIANS': (4, 'number of musicians inside the shop'), 'DATE_ESTABLISHED': (date(1972, 11, 30), "the shop's first opening"), 'MY_SELECT_KEY': ('yes', 'select yes or no', 'yes_no_null_select'), + 'MULTILINE': ('Line one\nLine two', 'multiline string'), } CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' diff --git a/tests/test_admin.py b/tests/test_admin.py index 6b13538b..06a08be0 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -11,6 +11,7 @@ from constance import settings from constance.admin import Config +from constance.admin import get_values class TestAdmin(TestCase): @@ -117,6 +118,26 @@ def test_submit(self): response = self.options.changelist_view(request, {}) self.assertIsInstance(response, HttpResponseRedirect) + @mock.patch('constance.settings.CONFIG_FIELDSETS', { + 'FieldSetOne': ('MULTILINE',) + }) + @mock.patch('constance.settings.CONFIG', { + 'MULTILINE': ('Hello\nWorld', 'multiline value'), + }) + @mock.patch('constance.settings.IGNORE_ADMIN_VERSION_CHECK', True) + def test_newlines_normalization(self): + self.client.login(username='admin', password='nimda') + request = self.rf.post('/admin/constance/config/', data={ + "MULTILINE": "Hello\r\nWorld", + "version": "123", + }) + request.user = self.superuser + request._dont_enforce_csrf_checks = True + with mock.patch("django.contrib.messages.add_message"): + response = self.options.changelist_view(request, {}) + self.assertIsInstance(response, HttpResponseRedirect) + self.assertEqual(get_values()['MULTILINE'], 'Hello\nWorld') + @mock.patch('constance.settings.CONFIG', { 'DATETIME_VALUE': (datetime(2019, 8, 7, 18, 40, 0), 'some naive datetime'), })