Закрыть

Для эффективной работы на сайте используются cookie и обработка персональных данных. Пользуясь этим сайтом, вы соглашаетесь с правилами использования сайта. Подробнее

Цитата дня

Vivazzi.ru

Личный сайт Мальцева Артема

В этом мире есть только один способ заслужить любовь - перестать требовать её и начать дарить любовь, не надеясь на благодарность.

Дейл Карнеги

Свои шаблоны для обработки ошибок 403, 404 в django

10 февраля 2016 г. 0:53

В зависимости от задач можно по-разному переопределить в Django стандартное поведение на реакцию ошибок, таких как 403, 404, 500 и стандартные шаблоны вывода ошибок. В официальной документации (на рус. яз. - http://djbook.ru/rel1.8/topics/http/views.html ) хорошо это описывается, но тем не менее есть некоторые нюансы, о которых я хочу рассказать и показать в примерах.

В большинстве случаев можно оставить стандартное поведение Django, т. е. стандартные views (из django.views.defaults), обрабатывающие ошибки и переопределить только шаблоны.

Допустим, у нас есть шаблон ошибки 404:

# 404.html
{% extends "base.html" %}

{% block subtitle %}Страница не найдена{% endblock %}
{% block meta %}<meta name="robots" content="noindex, nofollow">{% endblock %}

{% block content %}
    <h2>Запрашиваемая страница не найдена</h2>
    <p>Возможно, неправильно указан путь в адресной строке или страница была удалена.</p>
    <p>Возврат на <a href="/">главную страницу</a></p>
{% endblock %}

А ниже описаны разные способы переопределения.

Добавление своего шаблона в templates

Самый простой способ переопределения - это добавить этот шаблон в "my_project / templates". Именно здесь django будет искать шаблон 404.html и при наличии отрендерит.

Добавление своего шаблона в другую папку

Не всегда удобно держать шаблоны ошибок в "my_project / templates" вместе с какими-то другими шаблонами и хочется их вынести в отдельную папку. Я, к примеру, использую следующую структуру папки templates в корне проекта (жирным выделены папки):

  • admin - содержит переопределяемые админские шаблонов
  • cms - содержит переопределяемые шаблоны Django CMS
  • errs - содержит шаблоны ошибок
    • 403.html
    • 404.html
    • 500.html
  • vers - содержит проверочные файлы для поисковых систем
  • base.html
  • one_col.html
  • two_col.html
  • main.html

Как видите, вынос шаблонов ошибок в отдельную папку - хорошая идея отделить их от шаблонов страниц (one_col.html, two_col.html, main.html). Чтобы указать django, где искать шаблоны по новому пути, нужно использовать метод curry, например:

# urls.py
from django.views.defaults import server_error, page_not_found, permission_denied

handler403 = curry(permission_denied, template_name='errs/403.html')
handler404 = curry(page_not_found, template_name='errs/404.html')
handler500 = curry(server_error, template_name='errs/500.html')

Замечание: в Django>=1.9 нужно добавить ещё один аргумент exception для handler403 и handler404:

handler403 = curry(permission_denied, exception=Exception('Permission Denied'), template_name='errs/403.html')
handler404 = curry(page_not_found, exception=Exception('Page not Found'), template_name='errs/404.html')

Тестирование своих шаблонов ошибок

Чтобы протестировать шаблоны ошибок, достаточно добавить соответствующие urls в urls.py, например так:

if settings.DEBUG:
    urlpatterns = [
        url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
        url(r'', include('django.contrib.staticfiles.urls')),

        # --- error pages ---
        url(r'^403$', handler403),
        url(r'^404$', handler404),
        url(r'^500$', handler500),
    ] + urlpatterns

Теперь можно переходить по адресу http://localhost:8000/404 и видеть свой кастомный шаблон ошибки. На боевом сайте нам тестовые урлы ошибок не нужны, поэтому мы добавили их в условие if settings.DEBUG:.

Создание своего представления для обработки ошибки

Если хочется изменить стандартное поведение обработки ошибок, то нужно писать своё представление. Например:

# urls.py
handler403 = 'my_app.views.show_403'
handler404 = 'my_app.views.show_404'

# my_app/views.py
# Обработка ошибки 403
from django.core.exceptions import PermissionDenied
def show_403(request):
    # какие-либо действия
    raise PermissionDenied

# Обработка ошибки 404
from django.http.response import Http404
def show_404(request):
    # какие-либо действия
    raise Http404

Можно усложнить пример с обработкой ошибки 404. Например, мы хотим отдавать разные шаблоны 404 в зависимости от того, с чего начинается отсутствующий url:

# Обработка ошибки 404
from django.http.response import Http404
def 404(request):
    if request.path.startswith('/project/'):
        return render(request, 'project_not_found.html')  # выдаст страницу, что проекта нет и, к примеру, покажет другие проекты
    if request.path.startswith('/shop/'):
        return render(request, 'product_not_found.html')  # выдаст страницу, что товара нет и, к примеру, покажет другие товары

    raise Http404  # в остальных случаях показать стандартное исключение, которое отрендерит наш шаблон 404.html

Некоторые тонкости

Проверка отдачи шаблона 404

Для проверки отдачи шаблона 404 используйте при значении переменной DEBUG=False в settings.py, иначе вам будет показан трейсбек Django.

Внимание! Если DEBUG=False, то вы должны добавить в ALLOWED_HOSTSsettings.py) допустимые доменные имена, иначе Django будет выдавать ошибку “Bad Request (400)”. На локальной машине добавляется ‘localhost’ (или 127.0.0.1).

# settings.py
ALLOWED_HOSTS = ['localhost', ]

Обратите внимание, что при DEBUG=False статические файлы не будут показываться. Для показа статических файлов нужно собрать статику и запустить сервер с опцией --insecure:

python manage.py collectstatic
python manage.py runserver --insecure

Создание своего представления для обработки 500 ошибки

При использовании стандартного представления обработки 500 ошибки в соответствующий шаблон не передаётся контекст. Сделано так для того, чтобы уменьшить количество возможных других ошибок. Поэтому шаблон должен быть простой подобный этому:

<!DOCTYPE html>
<html>
<head>
    <title>Ошибка на стороне сервера</title>
    <meta name="robots" content="noindex, nofollow">
</head>
<body>
    <p>Извините, но что-то случилось с сайтом.</p>
    <p>В техническую поддержку уже отправлено уведомление.</p>
</body>
</html>

Если будете делать своё представление для 500 ошибки, то следуйте правилам django - не передавайте RequestContext при рендеринге шаблона. Посмотрите как происходит обработка в стандартном представлении django.views.defaults.server_error.

Отображение ошибок без рендеринга шаблонов

from django.http import HttpResponseNotFound 

def test_view_1(request, param):  
  if not param:  # какое-то условие
    return HttpResponseNotFound('<p>Страница не найдена</p>')  

  return render_to_response('test_view_1.html')  


from django.http.response import HttpResponseForbidden
def test_view_2(request, param):
    if not param:
        return HttpResponseForbidden('Доступ запрещён')

    return render_to_response('test_view_2.html')

Надеюсь, статья помогла ответить на возникающие вопросы об обработке ошибок в Django.

Оцените статью

3,7 из 5 (всего 3 оценки)

Поля, отмеченные звёздочкой ( * ) , являются обязательными.

Спасибо за ваш отзыв!

Автор статьи

Права на использование данной статьи, расположенной на настоящей странице http://vivazzi.ru/it/django-custom-templates-for-errors/:

Разрешается копировать статью с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Мальцев Артём
Ссылка на статью: <a href="http://vivazzi.ru/it/django-custom-templates-for-errors/">http://vivazzi.ru/it/django-custom-templates-for-errors/</a>

Подробнее: Правила использования сайта

Вам нужно саморазвиваться или вы хотите зарабатывать деньги?

Или вы ищите хорошие IT сервисы или книги? Сохраните свое время и взгляните на мою подборку рекомендаций, которыми постоянно пользуюсь.
Посмотреть рекомендации

Комментариев: 0

Вы можете оставить комментарий как незарегистрированный пользователь. Но, зарегистрировавшись, вы сможете получать оповещения об ответах, а также иметь доступ к своему личному аккаунту для просмотра своих комментариев.

Чтобы оставить комментарий от своего имени войдите или зарегистрируйтесь обычным способом или через социальные сети:

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте