Escribiendo vistas

Una función de vista o vista (view) es una función Python que toma una solicitud web y devuelve una respuesta web. Esta respuesta puede ser el contenido HTML de una página web, un redireccionamiento, un error 404, un documento XML u otra cosa. La propia vista contiene la lógica arbitraria necesaria para devolver esa respuesta. Este código puede vivir en cualquier lugar que desees, siempre y cuando esté en tu ruta Python. No hay ninguna otra requisito - no «magia», por así decirlo. Por el bien de poner el código en algún lugar, la convención es poner las vistas en un archivo llamado views.py, ubicado en tu directorio de proyecto o aplicación.

Una vista simple

Aquí tienes una vista que devuelve la fecha y hora actual, como documento HTML:

from django.http import HttpResponse
import datetime


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

Vamos a pasar por este código línea a línea:

  • Primero, importamos la clase HttpResponse del módulo django.http, junto con la biblioteca Python datetime.

  • A continuación, definimos una función llamada current_datetime. Esta es la función de vista. Cada función de vista toma un objeto HttpRequest como su primer parámetro, que a menudo se llama request.

    Nota que el nombre de la función de vista no importa; no tiene que llamarse de una cierta manera para que Django lo reconozca. Estamos llamándolo current_datetime aquí, porque ese nombre indica claramente qué hace.

  • La vista devuelve un objeto HttpResponse que contiene la respuesta generada. Cada función de vista es responsable de devolver un objeto HttpResponse. (Hay excepciones, pero llegaremos a ellas más adelante.)

Zona Horaria de Django

Django incluye un parámetro de configuración TIME_ZONE que tiene como valor predeterminado America/Chicago. Probablemente no es donde tú vives, por lo que podrías querer cambiarlo en tu archivo de configuración.

Mapear URLs a vistas

Así queda la traducción:

Devolviendo errores

Django proporciona ayuda para devolver códigos de error HTTP. Hay subclases de HttpResponse para un número de códigos de estado HTTP comunes distintos de 200 (que significa «OK»). Puedes encontrar la lista completa de las subclases disponibles en la documentación de solicitud/respuesta. Devuelve una instancia de una de esas subclases en lugar de un normal HttpResponse para significar un error. Por ejemplo:

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

No hay una subclase especializada para cada código de respuesta HTTP posible, ya que muchos de ellos no son tan comunes. Sin embargo, como se documenta en la documentación de HttpResponse, también puedes pasar el código de estado HTTP al constructor de HttpResponse para crear una clase de retorno para cualquier código de estado que desees. Por ejemplo:

from django.http import HttpResponse


def my_view(request):
    # ...

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

Porque los errores 404 son con mucho los errores HTTP más comunes, hay una forma más fácil de manejar esos errores.

La excepción Http404

class django.http.Http404

Cuando devuelves un error como HttpResponseNotFound, eres responsable de definir el HTML de la página de errores resultante:

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

Por conveniencia, y porque es una buena idea tener una página de errores 404 consistente a lo largo de tu sitio, Django proporciona la excepción Http404. Si levantas Http404 en algún punto de una función de vista, Django lo capturará y devolverá la página de error estándar para tu aplicación, junto con un código HTTP de error 404.

Since get_session_auth_hash() está basado en SECRET_KEY, los valores de la clave secreta deben rotarse para evitar invalidar las sesiones existentes cuando se actualiza el sitio para utilizar una nueva clave secreta. Consulte SECRET_KEY_FALLBACKS para obtener más detalles.

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

Para mostrar HTML personalizado cuando Django devuelve un 404, puedes crear un archivo de plantilla HTML llamado 404.html y colocarlo en el nivel superior de tu árbol de plantillas. Esta plantilla se servirá cuando DEBUG esté establecido en False.

Cuando DEBUG está True, puedes proporcionar un mensaje a Http404 y aparecerá en la plantilla de depuración 404 estándar. Utiliza estos mensajes para fines de depuración; generalmente no son adecuados para su uso en una plantilla de error 404 de producción.

Personalización de vistas de errores

Las vistas de errores predeterminadas de Django deberían ser suficientes para la mayoría de las aplicaciones web, pero se pueden sobrescribir fácilmente si necesitas algún comportamiento personalizado. Especifica los manejadores como se muestra a continuación en tu URLconf (establecerlos en cualquier otro lugar no tendrá efecto).

La vista page_not_found() se sobrescribe por handler404:

handler404 = "mysite.views.my_custom_page_not_found_view"

La vista server_error() se sobrescribe por handler500:

handler500 = "mysite.views.my_custom_error_view"

La vista permission_denied() se sobrescribe por handler403:

handler403 = "mysite.views.my_custom_permission_denied_view"

La vista bad_request() se sobrescribe por handler400:

handler400 = "mysite.views.my_custom_bad_request_view"

Ver también

Utiliza la configuración CSRF_FAILURE_VIEW para sobrescribir la vista de errores CSRF.

Testing custom error views

Prueba de vistas personalizadas de errores

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)

Vistas asíncronas

As well as being synchronous functions, views can also be asynchronous («async») functions, normally defined using Python’s async def syntax. Django will automatically detect these and run them in an async context. However, you will need to use an async server based on ASGI to get their performance benefits.

Aquí tienes un ejemplo de una vista asíncrona:

import datetime
from django.http import HttpResponse


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

You can read more about Django’s async support, and how to best use async views, in Soporte asíncrono.