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