Написание представлений

Функция представления, или сокращенно view, - это функция Python, которая принимает веб-запрос и возвращает веб-ответ. Этим ответом может быть HTML-содержимое веб-страницы, или перенаправление, или ошибка 404, или XML-документ, или изображение … или что угодно. Само представление содержит любую произвольную логику, необходимую для возврата ответа. Этот код может находиться где угодно, лишь бы он был в пути Python. Нет никаких других требований - никакой «магии», так сказать. Для того, чтобы код был где-то, принято помещать представления в файл с именем views.py, расположенный в каталоге проекта или приложения.

Простое представление

Вот представление, которое возвращает текущую дату и время в виде HTML-документа:

from django.http import HttpResponse
import datetime


def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

Давайте пройдемся по этому коду по одной строке за раз:

  • Сначала мы импортируем класс HttpResponse из модуля django.http вместе с библиотекой Python datetime.

  • Затем мы определяем функцию под названием current_datetime. Это функция просмотра. Каждая функция представления принимает в качестве первого параметра объект HttpRequest, который обычно называется request.

    Обратите внимание, что имя функции представления не имеет значения; его не нужно называть определенным образом, чтобы Django мог его распознать. Мы называем это здесь current_datetime, потому что это имя четко указывает на то, что он делает.

  • Представление возвращает объект HttpResponse, содержащий сгенерированный ответ. Каждая функция представления отвечает за возврат объекта HttpResponse. (Есть исключения, но мы вернемся к ним позже.)

Часовой пояс Джанго

Django включает параметр TIME_ZONE, который по умолчанию имеет значение Америка/Чикаго. Вероятно, это не то место, где вы живете, поэтому вы можете изменить это в своем файле настроек.

Сопоставление URL-адресов с представлениями

Итак, напомним, эта функция возвращает HTML-страницу, которая включает текущую дату и время. Чтобы отобразить это представление по определенному URL-адресу, вам необходимо создать URLconf; смотрите Диспетчер URL для получения инструкций.

Возврат ошибок

Django предоставляет помощь по возврату кодов ошибок HTTP. Существуют подклассы HttpResponse для ряда общих кодов состояния HTTP, кроме 200 (что означает «OK»). Вы можете найти полный список доступных подклассов в документации request/response. Вернуть экземпляр одного из этих подклассов вместо обычного HttpResponse, чтобы обозначить ошибку. Например:

from django.http import HttpResponse, HttpResponseNotFound


def my_view(request):
    # ...
    if foo:
        return HttpResponseNotFound("<h1>Page not found</h1>")
    else:
        return HttpResponse("<h1>Page was found</h1>")

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

from django.http import HttpResponse


def my_view(request):
    # ...

    # Return a "created" (201) response code.
    return HttpResponse(status=201)

Поскольку ошибки 404 являются наиболее распространенной ошибкой HTTP, есть более простой способ справиться с этими ошибками.

Исключение Http404

class django.http.Http404

Когда вы возвращаете ошибку, такую как HttpResponseNotFound, вы отвечаете за определение HTML страницы с ошибкой:

return HttpResponseNotFound("<h1>Page not found</h1>")

Для удобства, а также потому, что рекомендуется иметь последовательную страницу с ошибкой 404 на вашем сайте, Django предоставляет исключение Http404. Если вы вызовете Http404 в любой точке функции представления, Django поймает его и вернет стандартную страницу ошибки для вашего приложения вместе с кодом ошибки HTTP 404.

Пример использования:

from django.http import Http404
from django.shortcuts import render
from polls.models import Poll


def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404("Poll does not exist")
    return render(request, "polls/detail.html", {"poll": p})

Чтобы отображать настроенный HTML-код, когда Django возвращает 404, вы можете создать HTML-шаблон с именем 404.html и поместить его на верхний уровень вашего дерева шаблонов. Затем этот шаблон будет обслуживаться, если DEBUG имеет значение False.

Когда DEBUG имеет значение True, вы можете предоставить сообщение для Http404, и оно появится в стандартном шаблоне отладки 404. Используйте эти сообщения для отладки; они обычно не подходят для использования в рабочем шаблоне 404.

Настройка представлений ошибок

Стандартные представления ошибок в Django должны быть достаточными для большинства веб-приложений, но их можно легко переопределить, если вам нужно любое пользовательское поведение. Укажите обработчики, как показано ниже, в вашей URLconf (установка их в любом другом месте не будет иметь никакого эффекта).

Представление page_not_found() переопределяет handler404:

handler404 = "mysite.views.my_custom_page_not_found_view"

Представление server_error() переопределяет handler500:

handler500 = "mysite.views.my_custom_error_view"

Представление permission_denied() переопределяет handler403:

handler403 = "mysite.views.my_custom_permission_denied_view"

Представление bad_request() переопределяет handler400:

handler400 = "mysite.views.my_custom_bad_request_view"

См.также

Используйте параметр CSRF_FAILURE_VIEW, чтобы переопределить просмотр ошибок CSRF.

Тестирование пользовательских представлений ошибок

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

from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.test import SimpleTestCase, override_settings
from django.urls import path


def response_error_handler(request, exception=None):
    return HttpResponse("Error handler content", status=403)


def permission_denied_view(request):
    raise PermissionDenied


urlpatterns = [
    path("403/", permission_denied_view),
]

handler403 = response_error_handler


# ROOT_URLCONF must specify the module that contains handler403 = ...
@override_settings(ROOT_URLCONF=__name__)
class CustomErrorHandlerTests(SimpleTestCase):
    def test_handler_renders_template_response(self):
        response = self.client.get("/403/")
        # Make assertions on the response here. For example:
        self.assertContains(response, "Error handler content", status_code=403)

Асинхронные представления

Представления могут быть не только синхронными, но и асинхронными («async») функциями, обычно определяемыми с использованием синтаксиса Python async def. Django автоматически обнаружит их и запустит в асинхронном контексте. Однако вам нужно будет использовать асинхронный сервер на основе ASGI, чтобы получить их преимущества в производительности.

Вот пример асинхронного представления:

import datetime
from django.http import HttpResponse


async def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

Вы можете узнать больше о поддержке async в Django и о том, как лучше всего использовать асинхронные представления, в : doc:/topics/async.

Вернуться на верх