diff --git a/django/conf/__init__.py b/django/conf/__init__.py index cf91ce83d4..608ad256dc 100644 --- a/django/conf/__init__.py +++ b/django/conf/__init__.py @@ -16,14 +16,11 @@ from pathlib import Path import django from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured -from django.utils.deprecation import ( - RemovedInDjango30Warning, RemovedInDjango31Warning, -) +from django.utils.deprecation import RemovedInDjango31Warning from django.utils.functional import LazyObject, empty ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" -DEFAULT_CONTENT_TYPE_DEPRECATED_MSG = 'The DEFAULT_CONTENT_TYPE setting is deprecated.' FILE_CHARSET_DEPRECATED_MSG = ( 'The FILE_CHARSET setting is deprecated. Starting with Django 3.1, all ' 'files read from disk must be UTF-8 encoded.' @@ -115,20 +112,6 @@ class LazySettings(LazyObject): """Return True if the settings have already been configured.""" return self._wrapped is not empty - @property - def DEFAULT_CONTENT_TYPE(self): - stack = traceback.extract_stack() - # Show a warning if the setting is used outside of Django. - # Stack index: -1 this line, -2 the caller. - filename, _line_number, _function_name, _text = stack[-2] - if not filename.startswith(os.path.dirname(django.__file__)): - warnings.warn( - DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, - RemovedInDjango30Warning, - stacklevel=2, - ) - return self.__getattr__('DEFAULT_CONTENT_TYPE') - @property def FILE_CHARSET(self): stack = traceback.extract_stack() @@ -175,8 +158,6 @@ class Settings: if not self.SECRET_KEY: raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.") - if self.is_overridden('DEFAULT_CONTENT_TYPE'): - warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) if self.is_overridden('FILE_CHARSET'): warnings.warn(FILE_CHARSET_DEPRECATED_MSG, RemovedInDjango31Warning) @@ -223,9 +204,7 @@ class UserSettingsHolder: def __setattr__(self, name, value): self._deleted.discard(name) - if name == 'DEFAULT_CONTENT_TYPE': - warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) - elif name == 'FILE_CHARSET': + if name == 'FILE_CHARSET': warnings.warn(FILE_CHARSET_DEPRECATED_MSG, RemovedInDjango31Warning) super().__setattr__(name, value) diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 03aa87bf21..acee9887d2 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -164,10 +164,8 @@ USE_L10N = False # notifications and other various emails. MANAGERS = ADMINS -# Default content type and charset to use for all HttpResponse objects, if a -# MIME type isn't manually specified. These are used to construct the -# Content-Type header. -DEFAULT_CONTENT_TYPE = 'text/html' +# Default charset to use for all HttpResponse objects, if a MIME type isn't +# manually specified. It's used to construct the Content-Type header. DEFAULT_CHARSET = 'utf-8' # Encoding of files read from disk (template and initial SQL files). diff --git a/django/http/response.py b/django/http/response.py index f7d248e933..5a640a51cf 100644 --- a/django/http/response.py +++ b/django/http/response.py @@ -57,8 +57,7 @@ class HttpResponseBase: self._reason_phrase = reason self._charset = charset if content_type is None: - content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE, - self.charset) + content_type = 'text/html; charset=%s' % self.charset self['Content-Type'] = content_type @property @@ -427,7 +426,7 @@ class FileResponse(StreamingHttpResponse): elif hasattr(filelike, 'getbuffer'): self['Content-Length'] = filelike.getbuffer().nbytes - if self.get('Content-Type', '').startswith(settings.DEFAULT_CONTENT_TYPE): + if self.get('Content-Type', '').startswith('text/html'): if filename: content_type, encoding = mimetypes.guess_type(filename) # Encoding isn't set to prevent browsers from automatically diff --git a/django/views/defaults.py b/django/views/defaults.py index 8bf60c9d74..1176bdeeeb 100644 --- a/django/views/defaults.py +++ b/django/views/defaults.py @@ -47,7 +47,7 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): try: template = loader.get_template(template_name) body = template.render(context, request) - content_type = None # Django will use DEFAULT_CONTENT_TYPE + content_type = None # Django will use 'text/html'. except TemplateDoesNotExist: if template_name != ERROR_404_TEMPLATE_NAME: # Reraise if it's a missing custom template. diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt index 2d1bbdeb57..d220737340 100644 --- a/docs/ref/class-based-views/mixins-simple.txt +++ b/docs/ref/class-based-views/mixins-simple.txt @@ -83,7 +83,7 @@ Simple mixins The content type to use for the response. ``content_type`` is passed as a keyword argument to ``response_class``. Default is ``None`` -- - meaning that Django uses :setting:`DEFAULT_CONTENT_TYPE`. + meaning that Django uses ``'text/html'``. **Methods** diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index b04d3b9d17..9c75383ef0 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -748,7 +748,7 @@ Methods ``content_type`` is the MIME type optionally completed by a character set encoding and is used to fill the HTTP ``Content-Type`` header. If not - specified, it is formed by the :setting:`DEFAULT_CONTENT_TYPE` and + specified, it is formed by ``'text/html'`` and the :setting:`DEFAULT_CHARSET` settings, by default: "`text/html; charset=utf-8`". ``status`` is the :rfc:`HTTP status code <7231#section-6>` for the response. diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 0aefd6bce5..ef83842aa0 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -1195,24 +1195,7 @@ See also :setting:`NUMBER_GROUPING`, :setting:`THOUSAND_SEPARATOR` and Default: ``'utf-8'`` Default charset to use for all ``HttpResponse`` objects, if a MIME type isn't -manually specified. Used with :setting:`DEFAULT_CONTENT_TYPE` to construct the -``Content-Type`` header. - -.. setting:: DEFAULT_CONTENT_TYPE - -``DEFAULT_CONTENT_TYPE`` ------------------------- - -Default: ``'text/html'`` - -Default content type to use for all ``HttpResponse`` objects, if a MIME type -isn't manually specified. Used with :setting:`DEFAULT_CHARSET` to construct -the ``Content-Type`` header. - -.. deprecated:: 2.0 - - This setting is deprecated because it doesn't interact well with - third-party apps and is obsolete since HTML5 has mostly superseded XHTML. +manually specified. Used when constructing the ``Content-Type`` header. .. setting:: DEFAULT_EXCEPTION_REPORTER_FILTER @@ -3436,7 +3419,6 @@ HTTP * :setting:`DATA_UPLOAD_MAX_MEMORY_SIZE` * :setting:`DATA_UPLOAD_MAX_NUMBER_FIELDS` * :setting:`DEFAULT_CHARSET` -* :setting:`DEFAULT_CONTENT_TYPE` * :setting:`DISALLOWED_USER_AGENTS` * :setting:`FORCE_SCRIPT_NAME` * :setting:`INTERNAL_IPS` diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt index 6e2f736281..e51e99605e 100644 --- a/docs/ref/template-response.txt +++ b/docs/ref/template-response.txt @@ -76,7 +76,7 @@ Methods The value included in the HTTP ``Content-Type`` header, including the MIME type specification and the character set encoding. If ``content_type`` is specified, then its value is used. Otherwise, - :setting:`DEFAULT_CONTENT_TYPE` is used. + ``'text/html'`` is used. ``status`` The HTTP status code for the response. @@ -171,7 +171,7 @@ Methods The value included in the HTTP ``Content-Type`` header, including the MIME type specification and the character set encoding. If ``content_type`` is specified, then its value is used. Otherwise, - :setting:`DEFAULT_CONTENT_TYPE` is used. + ``'text/html'`` is used. ``status`` The HTTP status code for the response. diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt index c07a995bd6..ac69ab8714 100644 --- a/docs/releases/3.0.txt +++ b/docs/releases/3.0.txt @@ -240,6 +240,8 @@ to remove usage of these features. * ``django.shortcuts.render_to_response()`` is removed. +* The ``DEFAULT_CONTENT_TYPE`` setting is removed. + See :ref:`deprecated-features-2.1` for details on these changes, including how to remove usage of these features. diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt index a0eac39012..68e8fa3bf9 100644 --- a/docs/topics/http/shortcuts.txt +++ b/docs/topics/http/shortcuts.txt @@ -46,8 +46,8 @@ Optional arguments view will call it just before rendering the template. ``content_type`` - The MIME type to use for the resulting document. Defaults to the value of - the :setting:`DEFAULT_CONTENT_TYPE` setting. + The MIME type to use for the resulting document. Defaults to + ``'text/html'``. ``status`` The status code for the response. Defaults to ``200``. diff --git a/tests/view_tests/tests/test_default_content_type.py b/tests/view_tests/tests/test_default_content_type.py deleted file mode 100644 index ece88f4b19..0000000000 --- a/tests/view_tests/tests/test_default_content_type.py +++ /dev/null @@ -1,58 +0,0 @@ -import sys -from types import ModuleType - -from django.conf import DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, Settings, settings -from django.test import SimpleTestCase, ignore_warnings -from django.utils.deprecation import RemovedInDjango30Warning - - -class DefaultContentTypeTests(SimpleTestCase): - msg = DEFAULT_CONTENT_TYPE_DEPRECATED_MSG - - @ignore_warnings(category=RemovedInDjango30Warning) - def test_default_content_type_is_text_html(self): - """ - Content-Type of the default error responses is text/html. Refs #20822. - """ - with self.settings(DEFAULT_CONTENT_TYPE='text/xml'): - response = self.client.get('/raises400/') - self.assertEqual(response['Content-Type'], 'text/html') - - response = self.client.get('/raises403/') - self.assertEqual(response['Content-Type'], 'text/html') - - response = self.client.get('/nonexistent_url/') - self.assertEqual(response['Content-Type'], 'text/html') - - response = self.client.get('/server_error/') - self.assertEqual(response['Content-Type'], 'text/html') - - def test_override_settings_warning(self): - with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): - with self.settings(DEFAULT_CONTENT_TYPE='text/xml'): - pass - - def test_settings_init_warning(self): - settings_module = ModuleType('fake_settings_module') - settings_module.DEFAULT_CONTENT_TYPE = 'text/xml' - settings_module.SECRET_KEY = 'abc' - sys.modules['fake_settings_module'] = settings_module - try: - with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): - Settings('fake_settings_module') - finally: - del sys.modules['fake_settings_module'] - - def test_access_warning(self): - with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): - settings.DEFAULT_CONTENT_TYPE - # Works a second time. - with self.assertRaisesMessage(RemovedInDjango30Warning, self.msg): - settings.DEFAULT_CONTENT_TYPE - - @ignore_warnings(category=RemovedInDjango30Warning) - def test_access(self): - with self.settings(DEFAULT_CONTENT_TYPE='text/xml'): - self.assertEqual(settings.DEFAULT_CONTENT_TYPE, 'text/xml') - # Works a second time. - self.assertEqual(settings.DEFAULT_CONTENT_TYPE, 'text/xml')