GET- и POST-запросы. Обработчики исключений запросов

Курс по Django: https://stepik.org/a/183363

Архив проекта: 07_sitewomen.zip

Мы продолжаем тему URL. Те из вас, кто занимался веб-разработкой, знают, что структура URL-адреса может содержать дополнительные параметры в GET-запросах. Например, вот так:

http://127.0.0.1:8000/?name=Gagarina&cat=music

или так:

http://127.0.0.1:8000/cats/music/?name=Gagarina&type=pop

И так далее. Здесь у нас идет специальный стартовый символ – знак вопроса, после которого через амперсанд перечисляются различные параметры в виде пар ключ-значение. Так, через адресную строку можно передавать произвольные данные на сервер в виде таких GET-запросов.

Следующий вопрос, как можно выделять эти значения и обрабатывать их на стороне сервера в функциях представления? Для этого, как раз и существует параметр request – ссылка на объект HttpRequest. Через него мы можем обратиться к специальному словарю:

request.GET

где и хранятся все эти данные.

Поправим функцию представления categories_by_slug для отображения словаря GET в консоль:

def categories_by_slug(request, cat_slug):
    print(request.GET)
    return HttpResponse(f"<h1>Статьи по категориям</h1><p >slug: {cat_slug}</p>")

И выполним, например, такой запрос:

127.0.0.1:8000/cats/music/?name=Gagarina&type=pop

В консоли увидим значения:

<QueryDict: {'name': ['Gagarina'], 'type': ['pop']}>

Или, можем сначала проверить: есть ли в словаре какие-либо данные и только потом выводить их в консоль:

def categories_by_slug(request, cat_slug):
    if request.GET:
        print(request.GET)
 
    return HttpResponse(f"<h1>Статьи по категориям</h1><p >slug: {cat_slug}</p>")

Как видите, проверка делается очень просто. В дальнейшем мы будем использовать этот функционал.

Помимо GET-запросов в веб-программировании часто используются и POST-запросы. Они, обычно, связаны с передачей данных из форм и позже мы их тоже будем использовать. Здесь же я просто отмечу, что в этом случае вместо коллекции GET используется коллекция POST, а все остальное остается без изменений:

def categories_by_slug(request, cat_slug):
    if request.POST:
        print(request.POST)
 
    return HttpResponse(f"<h1>Статьи по категориям</h1>slug: {cat_slug}</p>")

Обработка исключений при запросах к серверу

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

http://127.0.0.1:8000/aaa

то мы увидим исключение 404 – страница не найдена. Такую информацию мы видим исключительно в процессе отладки нашего сайта, когда глобальная константа DEBUG в пакете конфигурации (файл settings.py) установлена в True.

Давайте посмотрим, что произойдет, если временно перевести ее в значение False. Перейдем в пакет конфигурации, откроем файл settings.py, найдем константу DEBUG и присвоим ей значение False. При запуске тестового сервера у нас возникнет ошибка, что мы должны указать разрешенные хосты. Так как мы сейчас используем хост 127.0.0.1, то его в виде строки и укажем:

ALLOWED_HOSTS = ['127.0.0.1']

Теперь сервер успешно запустился и при обновлении страницы мы уже видим более дружественную страницу без лишней отладочной информации. Но как нам ее поправить, чтобы отобразить более понятную информацию? Для этого в файле urls.py пакета конфигурации можно переопределить обработчик исключения 404. Для этого ему достаточно присвоить ссылку на функцию, которая и будет формировать ответ для отсутствующих страниц, например, так:

handler404 = page_not_found

Мы здесь передаем ссылку на функцию page_not_found, а саму функцию определим в приложении women:

def page_not_found(request, exception):
    return HttpResponseNotFound('<h1>Страница не найдена</h1>')

Обратите внимание, функция принимает два аргумента и возвращает ответ в виде экземпляра класса HttpResponseNotFound, которому передается HTML-страница, отображаемая при неверных запросах. Если теперь мы обновим страницу, то увидим заголовок «Страница не найдена».

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

Итак, мы предполагаем, что функция page_not_found будет вызываться всякий раз при возникновении исключения 404. И это важный момент. Смотрите, если в какой-либо другой функции представления сгенерировать это исключение, то будет автоматическое перенаправление на функцию page_not_found и пользователь увидит все ту же страницу 404. Например, в функции archive мы сделаем проверку:

from django.http import HttpResponse, HttpResponseNotFound, Http404
 
def archive(request, year):
    if year > 2023:
        raise Http404()
 
    return HttpResponse(f"<h1>Архив по годам</h1><p >{year}</p>")

Если год больше 2023-го, то генерируется исключение 404 как экземпляр класса Http404 и выполняется перенаправление на функцию page_not_found. Это нам позволяет описывать логику отображения неверных запросов в одном месте программы – в функции page_not_found.

Аналогичным образом можно переопределять обработчики других исключений, например:

  • handler500 – ошибка сервера;
  • handler403 – доступ запрещен;
  • handler400 – невозможно обработать запрос.

https://docs.djangoproject.com/en/4.2/ref/urls/

Но все они работают в боевом режиме при DEBUG = False. При отладке мы увидим расширенную служебную информацию, помогающую исправлять ошибки при разработке сайта.

Курс по Django: https://stepik.org/a/183363

Видео по теме