mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
WIP: Refs #35281 -- Unified and generalized request error handling.
This commit is contained in:
parent
2debd018db
commit
73b904c5e0
@ -1,9 +1,3 @@
|
||||
from django.urls import include
|
||||
from django.views import defaults
|
||||
|
||||
__all__ = ["handler400", "handler403", "handler404", "handler500", "include"]
|
||||
|
||||
handler400 = defaults.bad_request
|
||||
handler403 = defaults.permission_denied
|
||||
handler404 = defaults.page_not_found
|
||||
handler500 = defaults.server_error
|
||||
__all__ = ["include"]
|
||||
|
@ -131,7 +131,7 @@ def check_custom_error_handlers(app_configs, **kwargs):
|
||||
errors = []
|
||||
# All handlers take (request, exception) arguments except handler500
|
||||
# which takes (request).
|
||||
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]:
|
||||
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 2)]:
|
||||
try:
|
||||
handler = resolver.resolve_error_handler(status_code)
|
||||
except (ImportError, ViewDoesNotExist) as e:
|
||||
|
@ -211,6 +211,23 @@ class HttpResponseBase:
|
||||
def get(self, header, alternate=None):
|
||||
return self.headers.get(header, alternate)
|
||||
|
||||
@classmethod
|
||||
def response_class_by_status_code(cls, status_code):
|
||||
return {
|
||||
200: HttpResponse,
|
||||
301: HttpResponsePermanentRedirect,
|
||||
302: HttpResponseRedirect,
|
||||
304: HttpResponseNotModified,
|
||||
307: HttpResponseRedirect,
|
||||
308: HttpResponsePermanentRedirect,
|
||||
400: HttpResponseBadRequest,
|
||||
403: HttpResponseForbidden,
|
||||
404: HttpResponseNotFound,
|
||||
405: HttpResponseNotAllowed,
|
||||
410: HttpResponseGone,
|
||||
500: HttpResponseServerError,
|
||||
}.get(status_code, cls)
|
||||
|
||||
def set_cookie(
|
||||
self,
|
||||
key,
|
||||
|
@ -10,6 +10,7 @@ import functools
|
||||
import inspect
|
||||
import re
|
||||
import string
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from pickle import PicklingError
|
||||
from urllib.parse import quote
|
||||
@ -21,6 +22,7 @@ from django.core.checks import Error, Warning
|
||||
from django.core.checks.urls import check_resolver
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.deprecation import RemovedInDjango61Warning
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
|
||||
from django.utils.regex_helper import _lazy_re_compile, normalize
|
||||
@ -728,15 +730,26 @@ class URLResolver:
|
||||
raise ImproperlyConfigured(msg.format(name=self.urlconf_name)) from e
|
||||
return patterns
|
||||
|
||||
def resolve_error_handler(self, view_type):
|
||||
callback = getattr(self.urlconf_module, "handler%s" % view_type, None)
|
||||
if not callback:
|
||||
# No handler specified in file; use lazy import, since
|
||||
# django.conf.urls imports this file.
|
||||
from django.conf import urls
|
||||
|
||||
callback = getattr(urls, "handler%s" % view_type)
|
||||
def resolve_error_handler(self, status_code):
|
||||
# RemovedInDjango61Warning.
|
||||
callback = getattr(self.urlconf_module, f"handler{status_code}", None)
|
||||
if callback:
|
||||
warnings.warn(
|
||||
"handler<status> custom error handlers are deprecated, please "
|
||||
"replace them by a generic `error_handler` view function.",
|
||||
RemovedInDjango61Warning,
|
||||
)
|
||||
return get_callable(callback)
|
||||
error_view = getattr(self.urlconf_module, "error_handler", None)
|
||||
if error_view:
|
||||
error_view.status_code = status_code
|
||||
else:
|
||||
# No handler specified in file; use lazy import, since
|
||||
# django.views.defaults imports this file.
|
||||
from django.views.defaults import DefaultErrorView
|
||||
|
||||
error_view = DefaultErrorView.as_view(status_code=status_code)
|
||||
return error_view
|
||||
|
||||
def reverse(self, lookup_view, *args, **kwargs):
|
||||
return self._reverse_with_prefix(lookup_view, "", *args, **kwargs)
|
||||
|
@ -1,13 +1,17 @@
|
||||
from urllib.parse import quote
|
||||
|
||||
from django.http import (
|
||||
HttpResponse,
|
||||
HttpResponseBadRequest,
|
||||
HttpResponseForbidden,
|
||||
HttpResponseNotFound,
|
||||
HttpResponseServerError,
|
||||
)
|
||||
from django.template import Context, Engine, TemplateDoesNotExist, loader
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.debug import DEBUG_ENGINE
|
||||
from django.views.decorators.csrf import requires_csrf_token
|
||||
from django.views.generic.base import ContextMixin, View
|
||||
|
||||
ERROR_404_TEMPLATE_NAME = "404.html"
|
||||
ERROR_403_TEMPLATE_NAME = "403.html"
|
||||
@ -148,3 +152,63 @@ def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME)
|
||||
return HttpResponseForbidden(
|
||||
template.render(request=request, context={"exception": str(exception)})
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(requires_csrf_token, name="dispatch")
|
||||
class DefaultErrorView(ContextMixin, View):
|
||||
status_code = None
|
||||
context_by_status = {
|
||||
400: {"title": "Bad Request (400)", "details": ""},
|
||||
403: {"title": "403 Forbidden", "details": ""},
|
||||
404: {
|
||||
"title": "Not Found",
|
||||
"details": "The requested resource was not found on this server.",
|
||||
},
|
||||
500: {"title": "Server Error (500)", "details": ""},
|
||||
}
|
||||
|
||||
def setup(self, request, exception=None, **kwargs):
|
||||
self.exception = exception
|
||||
return super().setup(request, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
response_class = HttpResponse.response_class_by_status_code(self.status_code)
|
||||
context = self.get_context_data(**kwargs)
|
||||
try:
|
||||
template = loader.get_template(self.get_template_name())
|
||||
content = template.render(context, request)
|
||||
except TemplateDoesNotExist:
|
||||
template = DEBUG_ENGINE.from_string(ERROR_PAGE_TEMPLATE % context)
|
||||
content = template.render(context=Context(context))
|
||||
return response_class(content, status=self.status_code)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
def get_template_name(self):
|
||||
return f"{self.status_code}.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context |= self.context_by_status.get(
|
||||
self.status_code, {"title": f"Error ({self.status_code})", "details": ""}
|
||||
)
|
||||
context |= {
|
||||
"request_path": quote(self.request.path),
|
||||
"exception": self.exception_as_string(),
|
||||
}
|
||||
return context
|
||||
|
||||
def exception_as_string(self):
|
||||
if self.status_code == 404:
|
||||
# Try to get an "interesting" exception message, if any (and not the
|
||||
# ugly Resolver404 dictionary)
|
||||
try:
|
||||
message = self.exception.args[0]
|
||||
except (AttributeError, IndexError):
|
||||
pass
|
||||
else:
|
||||
if isinstance(message, str):
|
||||
return message
|
||||
return self.exception.__class__.__name__
|
||||
return str(self.exception)
|
||||
|
@ -1179,9 +1179,8 @@ details on these changes.
|
||||
``django.contrib.gis.utils`` will be removed.
|
||||
|
||||
* ``django.conf.urls.defaults`` will be removed. The functions
|
||||
``include()``, ``patterns()``, and ``url()``, plus
|
||||
:data:`~django.conf.urls.handler404` and :data:`~django.conf.urls.handler500`
|
||||
are now available through ``django.conf.urls``.
|
||||
``include()``, ``patterns()``, and ``url()``, plus ``handler404` and
|
||||
``handler500`` are now available through ``django.conf.urls``.
|
||||
|
||||
* The functions ``setup_environ()`` and ``execute_manager()`` will be removed
|
||||
from :mod:`django.core.management`. This also means that the old (pre-1.4)
|
||||
|
@ -187,6 +187,11 @@ By default, this is :func:`django.views.defaults.bad_request`. If you
|
||||
implement a custom view, be sure it accepts ``request`` and ``exception``
|
||||
arguments and returns an :class:`~django.http.HttpResponseBadRequest`.
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
The ``handler<code>`` handlers are deprecated and should be replaced by a
|
||||
generic ``error_handler`` view function.
|
||||
|
||||
``handler403``
|
||||
==============
|
||||
|
||||
@ -200,6 +205,12 @@ By default, this is :func:`django.views.defaults.permission_denied`. If you
|
||||
implement a custom view, be sure it accepts ``request`` and ``exception``
|
||||
arguments and returns an :class:`~django.http.HttpResponseForbidden`.
|
||||
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
The ``handler<code>`` handlers are deprecated and should be replaced by a
|
||||
generic ``error_handler`` view function.
|
||||
|
||||
``handler404``
|
||||
==============
|
||||
|
||||
@ -212,6 +223,12 @@ By default, this is :func:`django.views.defaults.page_not_found`. If you
|
||||
implement a custom view, be sure it accepts ``request`` and ``exception``
|
||||
arguments and returns an :class:`~django.http.HttpResponseNotFound`.
|
||||
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
The ``handler<code>`` handlers are deprecated and should be replaced by a
|
||||
generic ``error_handler`` view function.
|
||||
|
||||
``handler500``
|
||||
==============
|
||||
|
||||
@ -224,3 +241,8 @@ have runtime errors in view code.
|
||||
By default, this is :func:`django.views.defaults.server_error`. If you
|
||||
implement a custom view, be sure it accepts a ``request`` argument and returns
|
||||
an :class:`~django.http.HttpResponseServerError`.
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
The ``handler<code>`` handlers are deprecated and should be replaced by a
|
||||
generic ``error_handler`` view function.
|
||||
|
@ -58,8 +58,61 @@ parameter will be transparently passed to the view.
|
||||
Error views
|
||||
===========
|
||||
|
||||
Django comes with a few views by default for handling HTTP errors. To override
|
||||
these with your own custom views, see :ref:`customizing-error-views`.
|
||||
When any uncaught exception is produced by a view of your site, Django is
|
||||
calling an error handling view, which is by default the following view.
|
||||
|
||||
.. _default_error_view:
|
||||
|
||||
The default error view
|
||||
----------------------
|
||||
|
||||
.. class:: defaults.DefaultErrorView
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
The view is a class-based-view inheriting from
|
||||
:class:`~django.views.generic.base.ContextMixin`
|
||||
and class:`~django.views.generic.base.View`, so refer to theses classes for
|
||||
common attributes and methods.
|
||||
|
||||
.. attribute:: status_code
|
||||
|
||||
The status code of the HTTP response to return.
|
||||
|
||||
.. attribute:: exception
|
||||
|
||||
The exception that produced the error leading to the call of this error
|
||||
view.
|
||||
|
||||
.. method:: get_template_name()
|
||||
|
||||
Return by default a name on the pattern ``<status_code>.html``.
|
||||
|
||||
.. method:: exception_as_string()
|
||||
|
||||
Produce a string from the exception having triggered the error view.
|
||||
|
||||
If you provide any template in your root template directory named after an error
|
||||
response code (``404.html``, ``500.html``, etc.), that template will be used to
|
||||
produce an error path. Otherwise, Django will produce a very simple page
|
||||
containing an error title and a standard message.
|
||||
|
||||
The context used to render the error templates contains the following keys:
|
||||
|
||||
* ``title``: A short title for the error (like ``Not Found`` for a 404
|
||||
error).
|
||||
* ``details``: A short message explaining the error, possibley empty.
|
||||
* ``request_path``: The original request path of the view producing the
|
||||
error, quoted to prevent a content injection attack.
|
||||
* ``exception``: The uncaught exception that triggered the error view, as a
|
||||
string.
|
||||
|
||||
which either produces a "Not
|
||||
Found" message or loads and renders the template ``404.html`` if you created it
|
||||
in your root template directory.
|
||||
|
||||
To override this default view with your custom view, see
|
||||
:ref:`customizing-error-views`.
|
||||
|
||||
.. _http_not_found_view:
|
||||
|
||||
@ -68,6 +121,11 @@ The 404 (page not found) view
|
||||
|
||||
.. function:: defaults.page_not_found(request, exception, template_name='404.html')
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
This view is deprecated as it has been replaced by the :ref:`default error
|
||||
view <_default_error_view>`.
|
||||
|
||||
When you raise :exc:`~django.http.Http404` from within a view, Django loads a
|
||||
special view devoted to handling 404 errors. By default, it's the view
|
||||
:func:`django.views.defaults.page_not_found`, which either produces a "Not
|
||||
@ -99,6 +157,11 @@ The 500 (server error) view
|
||||
|
||||
.. function:: defaults.server_error(request, template_name='500.html')
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
This view is deprecated as it has been replaced by the :ref:`default error
|
||||
view <_default_error_view>`.
|
||||
|
||||
Similarly, Django executes special-case behavior in the case of runtime errors
|
||||
in view code. If a view results in an exception, Django will, by default, call
|
||||
the view ``django.views.defaults.server_error``, which either produces a
|
||||
@ -119,6 +182,11 @@ The 403 (HTTP Forbidden) view
|
||||
|
||||
.. function:: defaults.permission_denied(request, exception, template_name='403.html')
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
This view is deprecated as it has been replaced by the :ref:`default error
|
||||
view <_default_error_view>`.
|
||||
|
||||
In the same vein as the 404 and 500 views, Django has a view to handle 403
|
||||
Forbidden errors. If a view results in a 403 exception then Django will, by
|
||||
default, call the view ``django.views.defaults.permission_denied``.
|
||||
@ -148,6 +216,11 @@ The 400 (bad request) view
|
||||
|
||||
.. function:: defaults.bad_request(request, exception, template_name='400.html')
|
||||
|
||||
.. deprecated:: 5.2
|
||||
|
||||
This view is deprecated as it has been replaced by the :ref:`default error
|
||||
view <_default_error_view>`.
|
||||
|
||||
When a :exc:`~django.core.exceptions.SuspiciousOperation` is raised in Django,
|
||||
it may be handled by a component of Django (for example resetting the session
|
||||
data). If not specifically handled, Django will consider the current request a
|
||||
|
@ -342,25 +342,28 @@ Error handling
|
||||
When Django can't find a match for the requested URL, or when an exception is
|
||||
raised, Django invokes an error-handling view.
|
||||
|
||||
The views to use for these cases are specified by four variables. Their
|
||||
default values should suffice for most projects, but further customization is
|
||||
possible by overriding their default values.
|
||||
The default view Django uses for these cases is
|
||||
:class:`django.views.defaults.DefaultErrorView`. This view should suffice for
|
||||
most projects but further customization is possible by defining a custom view
|
||||
to handle errors, either by subclassing this view or by creating your own.
|
||||
|
||||
See the documentation on :ref:`customizing error views
|
||||
See the documentation on :ref:`customizing error view
|
||||
<customizing-error-views>` for the full details.
|
||||
|
||||
Such values can be set in your root URLconf. Setting these variables in any
|
||||
other URLconf will have no effect.
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
In previous versions, the views to use for these cases are specified by four
|
||||
variables.
|
||||
|
||||
Values must be callables, or strings representing the full Python import path
|
||||
to the view that should be called to handle the error condition at hand.
|
||||
|
||||
The variables are:
|
||||
|
||||
* ``handler400`` -- See :data:`django.conf.urls.handler400`.
|
||||
* ``handler403`` -- See :data:`django.conf.urls.handler403`.
|
||||
* ``handler404`` -- See :data:`django.conf.urls.handler404`.
|
||||
* ``handler500`` -- See :data:`django.conf.urls.handler500`.
|
||||
* ``handler400``
|
||||
* ``handler403``
|
||||
* ``handler404``
|
||||
* ``handler500``
|
||||
|
||||
.. _including-other-urlconfs:
|
||||
|
||||
|
@ -138,13 +138,26 @@ template.
|
||||
|
||||
.. _customizing-error-views:
|
||||
|
||||
Customizing error views
|
||||
=======================
|
||||
Customizing error view
|
||||
======================
|
||||
|
||||
The default error views in Django should suffice for most web applications,
|
||||
but can easily be overridden if you need any custom behavior. Specify the
|
||||
handlers as seen below in your URLconf (setting them anywhere else will have no
|
||||
effect).
|
||||
The default error view in Django should suffice for most web applications, but
|
||||
but can easily be overridden if you need any custom behavior.
|
||||
|
||||
The default error view can be overridden by setting a view in the
|
||||
``error_handler`` variable in your URLconf (setting it anywhere else will have
|
||||
no effect)::
|
||||
|
||||
error_handler = views.my_custom_error_view
|
||||
|
||||
or if you have a class-based-view::
|
||||
|
||||
error_handler = views.MyCustomErrorView.as_view()
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
On previous versions, there are multiple variables to define to override
|
||||
particular views.
|
||||
|
||||
The :func:`~django.views.defaults.page_not_found` view is overridden by
|
||||
:data:`~django.conf.urls.handler404`::
|
||||
|
@ -8,8 +8,9 @@ from django.core.checks.urls import (
|
||||
check_url_settings,
|
||||
get_warning_for_invalid_pattern,
|
||||
)
|
||||
from django.test import SimpleTestCase
|
||||
from django.test import SimpleTestCase, ignore_warnings
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.deprecation import RemovedInDjango61Warning
|
||||
|
||||
|
||||
class CheckUrlConfigTests(SimpleTestCase):
|
||||
@ -243,10 +244,11 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.bad_function_based_error_handlers",
|
||||
)
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_bad_function_based_handlers(self):
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(len(result), 4)
|
||||
for code, num_params, error in zip([400, 403, 404, 500], [2, 2, 2, 1], result):
|
||||
for code, error in zip([400, 403, 404, 500], result):
|
||||
with self.subTest("handler{}".format(code)):
|
||||
self.assertEqual(
|
||||
error,
|
||||
@ -254,9 +256,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
"The custom handler{} view 'check_framework.urls."
|
||||
"bad_function_based_error_handlers.bad_handler' "
|
||||
"does not take the correct number of arguments "
|
||||
"(request{}).".format(
|
||||
code, ", exception" if num_params == 2 else ""
|
||||
),
|
||||
"(request, exception).".format(code),
|
||||
id="urls.E007",
|
||||
),
|
||||
)
|
||||
@ -264,10 +264,11 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.bad_class_based_error_handlers",
|
||||
)
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_bad_class_based_handlers(self):
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(len(result), 4)
|
||||
for code, num_params, error in zip([400, 403, 404, 500], [2, 2, 2, 1], result):
|
||||
for code, error in zip([400, 403, 404, 500], result):
|
||||
with self.subTest("handler%s" % code):
|
||||
self.assertEqual(
|
||||
error,
|
||||
@ -275,11 +276,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
"The custom handler%s view 'check_framework.urls."
|
||||
"bad_class_based_error_handlers.HandlerView.as_view."
|
||||
"<locals>.view' does not take the correct number of "
|
||||
"arguments (request%s)."
|
||||
% (
|
||||
code,
|
||||
", exception" if num_params == 2 else "",
|
||||
),
|
||||
"arguments (request, exception)." % code,
|
||||
id="urls.E007",
|
||||
),
|
||||
)
|
||||
@ -287,6 +284,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.bad_error_handlers_invalid_path"
|
||||
)
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_bad_handlers_invalid_path(self):
|
||||
result = check_custom_error_handlers(None)
|
||||
paths = [
|
||||
@ -318,6 +316,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.good_function_based_error_handlers",
|
||||
)
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_good_function_based_handlers(self):
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(result, [])
|
||||
@ -325,6 +324,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.good_class_based_error_handlers",
|
||||
)
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_good_class_based_handlers(self):
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(result, [])
|
||||
|
@ -22,7 +22,8 @@ from django.middleware.csrf import (
|
||||
get_token,
|
||||
rotate_token,
|
||||
)
|
||||
from django.test import SimpleTestCase, override_settings
|
||||
from django.test import SimpleTestCase, ignore_warnings, override_settings
|
||||
from django.utils.deprecation import RemovedInDjango61Warning
|
||||
from django.views.decorators.csrf import csrf_exempt, requires_csrf_token
|
||||
|
||||
from .views import (
|
||||
@ -1477,6 +1478,7 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest
|
||||
|
||||
@override_settings(ROOT_URLCONF="csrf_tests.csrf_token_error_handler_urls", DEBUG=False)
|
||||
class CsrfInErrorHandlingViewsTests(CsrfFunctionTestMixin, SimpleTestCase):
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_csrf_token_on_404_stays_constant(self):
|
||||
response = self.client.get("/does not exist/")
|
||||
# The error handler returns status code 599.
|
||||
|
@ -1,7 +1,13 @@
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import SimpleTestCase, modify_settings, override_settings
|
||||
from django.test import (
|
||||
SimpleTestCase,
|
||||
ignore_warnings,
|
||||
modify_settings,
|
||||
override_settings,
|
||||
)
|
||||
from django.urls import path
|
||||
from django.utils.deprecation import RemovedInDjango61Warning
|
||||
|
||||
|
||||
class MiddlewareAccessingContent:
|
||||
@ -38,6 +44,7 @@ handler403 = template_response_error_handler
|
||||
}
|
||||
)
|
||||
class CustomErrorHandlerTests(SimpleTestCase):
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_handler_renders_template_response(self):
|
||||
"""
|
||||
BaseHandler should render TemplateResponse if necessary.
|
||||
|
@ -13,7 +13,13 @@ from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.http import HttpRequest, HttpResponsePermanentRedirect, HttpResponseRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.test import RequestFactory, SimpleTestCase, TestCase, override_settings
|
||||
from django.test import (
|
||||
RequestFactory,
|
||||
SimpleTestCase,
|
||||
TestCase,
|
||||
ignore_warnings,
|
||||
override_settings,
|
||||
)
|
||||
from django.test.utils import override_script_prefix
|
||||
from django.urls import (
|
||||
NoReverseMatch,
|
||||
@ -32,6 +38,7 @@ from django.urls import (
|
||||
reverse_lazy,
|
||||
)
|
||||
from django.urls.resolvers import RegexPattern
|
||||
from django.utils.deprecation import RemovedInDjango61Warning
|
||||
|
||||
from . import middleware, urlconf_outer, views
|
||||
from .utils import URLObject
|
||||
@ -1473,12 +1480,15 @@ class ErrorHandlerResolutionTests(SimpleTestCase):
|
||||
self.resolver = URLResolver(RegexPattern(r"^$"), urlconf)
|
||||
self.callable_resolver = URLResolver(RegexPattern(r"^$"), urlconf_callables)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_named_handlers(self):
|
||||
for code in [400, 403, 404, 500]:
|
||||
with self.subTest(code=code):
|
||||
self.assertEqual(self.resolver.resolve_error_handler(code), empty_view)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango61Warning)
|
||||
def test_callable_handlers(self):
|
||||
# After Django 6.1 removal, only test with 'error_handler' and one code.
|
||||
for code in [400, 403, 404, 500]:
|
||||
with self.subTest(code=code):
|
||||
self.assertEqual(
|
||||
|
@ -4,7 +4,9 @@ from .views import empty_view
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
# RemovedInDjango61Warning: the handler<...> variables can be removed
|
||||
handler400 = empty_view
|
||||
handler403 = empty_view
|
||||
handler404 = empty_view
|
||||
handler500 = empty_view
|
||||
error_handler = empty_view
|
||||
|
@ -1,4 +1,4 @@
|
||||
# A URLconf that doesn't define any handlerXXX.
|
||||
# A URLconf that doesn't define any error handler view.
|
||||
from django.urls import path
|
||||
|
||||
from .views import bad_view, empty_view
|
||||
|
Loading…
Reference in New Issue
Block a user