Создание представлений¶
Функция просмотра, или для краткости 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и библиотеку Pythondatetime.Теперь определим функцию
current_datetime. Это функция представления. Каждая функция представления принимает объектHttpRequestпервым аргументом, который обычно называютrequest.Название функции может быть каким угодно, нет никаких конкретных правил для именования. Мы назвали функцию
current_datetime.Представление возвращает объект
HttpResponse, который содержит сгенерированный ответ. Каждая функция представления должна возвращать объектHttpResponse. (Есть исключения, но мы расскажем об этом далее.)
Часовые пояса в Django
Django содержит настройку TIME_ZONE равную по умолчанию America/Chicago. Возможно это не там, где вы живете, вы можете изменить эту настройку в файле настройки.
Сопоставление представления с URL¶
Итак, напомним, функция представления возвращает HTML-страницу, которая содержит текущую дату и время. Чтобы привязать это представление к определенному URL-у, необходимо создать URLconf; подробности смотрите в разделе Менеджер URL-ов.
Возвращение ошибок¶
Возвращение HTTP ошибок в Django очень просто. Существует ряд подклассов HttpResponse для распространенных HTTP-состояний, отличных от 200 (что означает «OK»). Вы можете посмотреть полный список доступных подклассов в разделе о HTTP запросах и ответах. Просто верните экземпляр необходимого подкласса вместо 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 перехватит его и вернет стандартную страницу 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. Используйте эти сообщения для отладки; сообщения не отображаются при отключенной отладке.
Настройка представления обрабатывающего ошибки¶
Представления ошибок по умолчанию в Django должны быть достаточными для большинства веб-приложений, но их можно легко переопределить, если вам нужно какое-либо собственное поведение. Укажите обработчики, как показано ниже, в вашей конфигурации URL (их установка в другом месте не будет иметь никакого эффекта).
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.
Настройка представления обрабатывающего ошибки¶
Чтобы проверить реакцию пользовательского обработчика ошибок, вызовите соответствующее исключение в тестовом представлении. Например:
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)
Асинхронные представления¶
Помимо того, что представления являются синхронными функциями, они также могут быть асинхронными («асинхронными») функциями, обычно определяемыми с использованием синтаксиса 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)
Вы можете прочитать больше о поддержке асинхронности в Django и о том, как лучше всего использовать асинхронные представления, в Асинхронная поддержка.