Создание представлений

A view function, or view for short, is a Python function that takes a Web request and returns a Web response. This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything, really. The view itself contains whatever arbitrary logic is necessary to return that response. This code can live anywhere you want, as long as it’s on your Python path. There’s no other requirement–no «magic,» so to speak. For the sake of putting the code somewhere, the convention is to put views in a file called views.py, placed in your project or application directory.

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

Вот пример простого представления, которое отображает текущую дату и время, как документ 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.

    Название функции может быть каким угодно, нет никаких конкретных правил для именования. Мы назвали функцию current_datetime.

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

Часовые пояса в Django

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

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

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

Возвращение ошибок

Django provides help for returning HTTP error codes. There are subclasses of HttpResponse for a number of common HTTP status codes other than 200 (which means «OK»). You can find the full list of available subclasses in the request/response documentation. Return an instance of one of those subclasses instead of a normal HttpResponse in order to signify an error. For example:

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 перехватит его и вернет стандартную страницу 404 ошибки вашего проекта вместе с 404 кодом состояния HTTP.

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

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})

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

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

Настройка представления обрабатывающего ошибки

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).

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, используйте настройку CSRF_FAILURE_VIEW.

Testing custom error views

To test the response of a custom error handler, raise the appropriate exception in a test view. For example:

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)