You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

defaults.py 4.4KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from urllib.parse import quote
  2. from django.http import (
  3. HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotFound,
  4. HttpResponseServerError,
  5. )
  6. from django.template import Context, Engine, TemplateDoesNotExist, loader
  7. from django.views.decorators.csrf import requires_csrf_token
  8. ERROR_404_TEMPLATE_NAME = '404.html'
  9. ERROR_403_TEMPLATE_NAME = '403.html'
  10. ERROR_400_TEMPLATE_NAME = '400.html'
  11. ERROR_500_TEMPLATE_NAME = '500.html'
  12. # This can be called when CsrfViewMiddleware.process_view has not run,
  13. # therefore need @requires_csrf_token in case the template needs
  14. # {% csrf_token %}.
  15. @requires_csrf_token
  16. def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME):
  17. """
  18. Default 404 handler.
  19. Templates: :template:`404.html`
  20. Context:
  21. request_path
  22. The path of the requested URL (e.g., '/app/pages/bad_page/'). It's
  23. quoted to prevent a content injection attack.
  24. exception
  25. The message from the exception which triggered the 404 (if one was
  26. supplied), or the exception class name
  27. """
  28. exception_repr = exception.__class__.__name__
  29. # Try to get an "interesting" exception message, if any (and not the ugly
  30. # Resolver404 dictionary)
  31. try:
  32. message = exception.args[0]
  33. except (AttributeError, IndexError):
  34. pass
  35. else:
  36. if isinstance(message, str):
  37. exception_repr = message
  38. context = {
  39. 'request_path': quote(request.path),
  40. 'exception': exception_repr,
  41. }
  42. try:
  43. template = loader.get_template(template_name)
  44. body = template.render(context, request)
  45. content_type = None # Django will use DEFAULT_CONTENT_TYPE
  46. except TemplateDoesNotExist:
  47. if template_name != ERROR_404_TEMPLATE_NAME:
  48. # Reraise if it's a missing custom template.
  49. raise
  50. # Render template (even though there are no substitutions) to allow
  51. # inspecting the context in tests.
  52. template = Engine().from_string(
  53. '<h1>Not Found</h1>'
  54. '<p>The requested resource was not found on this server.</p>')
  55. body = template.render(Context(context))
  56. content_type = 'text/html'
  57. return HttpResponseNotFound(body, content_type=content_type)
  58. @requires_csrf_token
  59. def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
  60. """
  61. 500 error handler.
  62. Templates: :template:`500.html`
  63. Context: None
  64. """
  65. try:
  66. template = loader.get_template(template_name)
  67. except TemplateDoesNotExist:
  68. if template_name != ERROR_500_TEMPLATE_NAME:
  69. # Reraise if it's a missing custom template.
  70. raise
  71. return HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html')
  72. return HttpResponseServerError(template.render())
  73. @requires_csrf_token
  74. def bad_request(request, exception, template_name=ERROR_400_TEMPLATE_NAME):
  75. """
  76. 400 error handler.
  77. Templates: :template:`400.html`
  78. Context: None
  79. """
  80. try:
  81. template = loader.get_template(template_name)
  82. except TemplateDoesNotExist:
  83. if template_name != ERROR_400_TEMPLATE_NAME:
  84. # Reraise if it's a missing custom template.
  85. raise
  86. return HttpResponseBadRequest('<h1>Bad Request (400)</h1>', content_type='text/html')
  87. # No exception content is passed to the template, to not disclose any sensitive information.
  88. return HttpResponseBadRequest(template.render())
  89. # This can be called when CsrfViewMiddleware.process_view has not run,
  90. # therefore need @requires_csrf_token in case the template needs
  91. # {% csrf_token %}.
  92. @requires_csrf_token
  93. def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME):
  94. """
  95. Permission denied (403) handler.
  96. Templates: :template:`403.html`
  97. Context: None
  98. If the template does not exist, an Http403 response containing the text
  99. "403 Forbidden" (as per RFC 7231) will be returned.
  100. """
  101. try:
  102. template = loader.get_template(template_name)
  103. except TemplateDoesNotExist:
  104. if template_name != ERROR_403_TEMPLATE_NAME:
  105. # Reraise if it's a missing custom template.
  106. raise
  107. return HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html')
  108. return HttpResponseForbidden(
  109. template.render(request=request, context={'exception': str(exception)})
  110. )