Vistas Basadas en Clases

Vistas Basadas en Clases
Photo by Luke Heibert / Unsplash

Cuando Django se actualizó a la versión 1.5 aproveché para reescribir buena parte de las vistas del blog[1] utilizando Class Based Views (CBV) o Vistas Basadas en Clases.

La migración afectó principalmente a las vistas que generan listas —archivo por año, mes y día, categorías, etiquetas y portada— además de la vista que muestra las entradas individuales.

Hasta ese momento había utilizado exclusivamente vistas basadas en funciones (Function Based Views). Funcionaban bien, pero conforme el proyecto crecía comenzaban a aparecer patrones repetitivos. Muchas vistas hacían exactamente lo mismo: obtener un objeto, consultar un conjunto de registros, paginar resultados o mostrar una plantilla.

Las CBV fueron diseñadas precisamente para resolver ese problema.

En lugar de escribir una función completa para cada vista, Django proporciona una serie de clases genéricas que ya implementan la mayor parte del comportamiento habitual. Nosotros únicamente indicamos qué modelo utilizar, qué plantilla renderizar o qué consulta realizar.

Por ejemplo, ésta es la vista que utilizo para mostrar una entrada individual.

class EntradaIndividual(DateDetailView):
    date_field = "pub_date"
    model = Entry
    slug_field = "slug"
    template_name = "blog/single.html"

Eso es todo.

No hay consultas manuales, ni llamadas explícitas a render(), ni código para buscar el objeto correspondiente. Todo ese trabajo ya lo realiza DateDetailView; nosotros únicamente proporcionamos la configuración necesaria.

Las vistas genéricas disponibles

Django incluye un conjunto bastante amplio de vistas genéricas y vale la pena conocerlas antes de comenzar a escribir nuestras propias clases.

Todas ellas pertenecen al módulo django.views.generic.

Clase Descripción Ejemplo de uso
View Clase base para crear cualquier vista Una vista completamente personalizada
RedirectView Redirecciona al usuario Un acortador de direcciones
TemplateView Renderiza una plantilla Una página estática
ListView Muestra una colección de objetos Una categoría del blog
DetailView Muestra un único objeto Un artículo
FormView Procesa formularios Un formulario de contacto
CreateView Crea nuevos registros Crear un artículo
UpdateView Actualiza registros existentes Editar un artículo
DeleteView Elimina un registro Borrar una entrada
Vistas basadas en fechas Navegación cronológica Archivo anual, mensual o diario

Conocer estas clases evita escribir mucho código que Django ya resuelve por nosotros.

Un ejemplo sencillo: la portada

La portada del blog utiliza una ListView.

El código necesario para construirla es sorprendentemente pequeño.

class BlogArchivo(ListView):
    queryset = Entry.objects.order_by('-pub_date', 'id')
    paginate_by = 6
    template_name = 'portada.html'

Con únicamente tres atributos obtenemos una vista capaz de:

  • ejecutar la consulta;
  • ordenar los resultados;
  • paginar automáticamente;
  • enviar los datos a la plantilla correspondiente.

Gran parte del trabajo desaparece porque ya está implementado dentro de ListView.

Cuando necesitamos personalizar la consulta

Naturalmente no todas las vistas son tan simples.

Las categorías, por ejemplo, necesitan construir el QuerySet utilizando el slug recibido en la URL.

En ese caso basta con sobreescribir get_queryset().

class CategoriaList(ListView):
    paginate_by = 5
    template_name = "categoria.html"
    make_object_list = True
    context_object_name = 'categoria_list'

    def get_queryset(self):
        self.cat = get_object_or_404(Categoria, slug=self.args[0])
        return Entry.objects.filter(category=self.cat).order_by('-pub_date', 'id')

    def get_context_data(self, **kwargs):
        context = super(CategoriaList, self).get_context_data(**kwargs)
        context['cat'] = self.cat
        return context

Aquí la vista sigue aprovechando toda la infraestructura de ListView, pero sustituye únicamente la parte que realmente necesita personalizar.

Además, mediante get_context_data() agregamos información adicional que la plantilla utilizará para mostrar el nombre y los datos de la categoría actual.

Menos código, más intención

Eso es precisamente lo que más me gusta de las Vistas Basadas en Clases.

No se trata únicamente de escribir menos líneas de código.

Se trata de escribir clases que describen claramente cuál es su responsabilidad.

Al leer una clase que hereda de ListView sabemos inmediatamente que mostrará una colección de objetos. Si hereda de DetailView, sabemos que trabajará con un único registro. La propia jerarquía de clases se convierte en una forma de documentar la intención de cada vista.

Después de migrar el blog descubrí que muchas de las funciones que había escrito simplemente dejaron de ser necesarias. Django ya ofrecía soluciones para la mayoría de esos casos y bastaba con configurarlas adecuadamente.

Ésa es probablemente la mayor ventaja de las CBV: permiten concentrarnos en aquello que hace diferente a nuestra aplicación y dejar que el framework resuelva el resto.


  1. En ese tiempo el blog era ConxB, que ya no se encuentra operativo. Nada se ha perdido; poco a poco todo su contenido será incorporado a namespace.mx. ↩︎