Esta publicación es la quinta de la serie de vistas basadas en clases (CBV) de Django, y trata sobre cómo implementar fácilmente CRUD utilizando CreateView, UpdateView y DeleteView. Junto con las vistas ListView y DetailView que se abordaron en el artículo anterior, puedes construir rápidamente una aplicación CRUD completa que permita no solo consultar datos, sino también crear (Create), actualizar (Update) y eliminar (Delete) registros.

Recomiendo a aquellos que no han leído el artículo anterior sobre ListView y DetailView que lo hagan primero.

Explorando la serie de vistas basadas en clases (CBV) ④ - Cómo utilizar ListView & DetailView


“Completa fácilmente el CRUD con las vistas genéricas de Django y maximiza tu productividad!”

En las publicaciones anteriores, nos hemos centrado en la estructura básica de CBV y en las operaciones de lectura (READ) utilizando ListView y DetailView.
En esta publicación, exploraremos las convenientes CreateView, UpdateView y DeleteView que ofrece Django, para crear una aplicación web estructurada que incluya las funcionalidades de creación (Create), actualización (Update) y eliminación (Delete).


1. CreateView – Crear datos

1.1 Conceptos básicos y estructura

CreateView es una clase especializada dentro de las vistas genéricas de Django que se dedica a “crear nuevos objetos”.

  • Automatización del manejo de formularios: utilizando internamente la funcionalidad de FormView, guarda el nuevo objeto dentro de form_valid() y redirige a la URL de éxito.

  • Compatible con ModelForm: al establecer propiedades como model y fields, o form_class, se genera y procesa automáticamente el formulario.

# views.py
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Post

class PostCreateView(CreateView):
    model = Post
    fields = ['title', 'content']  # o form_class = PostForm
    template_name = 'post_form.html'
    success_url = reverse_lazy('post_list')  # URL a la que se redirigirá al éxito

1.2 Ejemplo de conexión en urls.py

# urls.py
from django.urls import path
from .views import PostCreateView

urlpatterns = [
    path('posts/create/', PostCreateView.as_view(), name='post_create'),
]

1.3 Ejemplo de plantilla: post_form.html

<!DOCTYPE html>
<html>
<head>
    <title>Escribiendo un nuevo artículo</title>
</head>
<body>
    <h1>Crear nuevo artículo</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Guardar</button>
    </form>
</body>
</html>

Consejo: Al usar form_class en lugar de fields, puedes definir un ModelForm en forms.py para un control más detallado del formulario.


2. UpdateView – Modificar datos

2.1 Conceptos básicos y estructura

UpdateView es una vista genérica dedicada a buscar y modificar un objeto existente.

  • Utiliza el valor pk o slug en la URL para buscar automáticamente el objeto correspondiente.

  • El formulario se renderiza con los datos existentes ya llenos, y cuando el usuario lo modifica y lo envía, se guardan los cambios en la base de datos.

# views.py
from django.views.generic.edit import UpdateView
from django.urls import reverse_lazy
from .models import Post

class PostUpdateView(UpdateView):
    model = Post
    fields = ['title', 'content']
    template_name = 'post_form.html'
    success_url = reverse_lazy('post_list')  # URL a la que se redirigirá al éxito

2.2 Ejemplo de conexión en urls.py

# urls.py
from .views import PostUpdateView

urlpatterns = [
    path('posts/<int:pk>/edit/', PostUpdateView.as_view(), name='post_update'),
]

2.3 Ejemplo de plantilla (reutilizable)

Al igual que el CreateView, también puedes reutilizar la plantilla post_form.html.
En UpdateView, form.instance ya es un objeto guardado en DB, por lo que los datos existentes se llenan automáticamente en el formulario.


3. DeleteView – Eliminar datos

3.1 Conceptos básicos y estructura

DeleteView es una vista genérica utilizada para buscar y eliminar un objeto específico.

  • Cuando el usuario envía el formulario de confirmación de eliminación, el objeto se elimina de la base de datos y se redirige a la URL especificada.

  • Por razones de seguridad, se recomienda tener una plantilla de “confirmación de eliminación”.

# views.py
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from .models import Post

class PostDeleteView(DeleteView):
    model = Post
    template_name = 'post_confirm_delete.html'
    success_url = reverse_lazy('post_list')

3.2 Ejemplo de conexión en urls.py

# urls.py
from .views import PostDeleteView

urlpatterns = [
    path('posts/<int:pk>/delete/', PostDeleteView.as_view(), name='post_delete'),
]

3.3 Ejemplo de plantilla: post_confirm_delete.html

<!DOCTYPE html>
<html>
<head>
    <title>Eliminar artículo</title>
</head>
<body>
    <h1>Eliminar artículo</h1>
    <p>¿Estás seguro de que deseas eliminar este artículo?</p>
    <form method="post">
        {% csrf_token %}
        <button type="submit">Eliminar</button>
        <a href="{% url 'post_list' %}">Cancelar</a>
    </form>
</body>
</html>

Nota: DeleteView está diseñado para pasar por un proceso de “confirmación de eliminación” para evitar la eliminación por error del usuario.
Si deseas eliminar directamente, debes implementarlo de otra manera (por ejemplo, utilizando FormView o escribiendo la lógica directamente).


4. Vista general del flujo para completar CRUD

Diagrama conceptual de CRUD – 4 Acciones, 5 Vistas

4.1 Modelo de ejemplo: Post

# models.py
class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return self.title

4.2 urlpatterns (versión abreviada)

urlpatterns = [
    # 1) LECTURA
    path('posts/', PostListView.as_view(), name='post_list'),                   # Lista (ListView)
    path('posts/<int:pk>/', PostDetailView.as_view(), name='post_detail'),      # Detalle (DetailView)

    # 2) CREAR
    path('posts/create/', PostCreateView.as_view(), name='post_create'),

    # 3) ACTUALIZAR
    path('posts/<int:pk>/edit/', PostUpdateView.as_view(), name='post_update'),

    # 4) ELIMINAR
    path('posts/<int:pk>/delete/', PostDeleteView.as_view(), name='post_delete'),
]

4.3 Estructura de carpetas recomendadas y archivos de plantilla

  • templates/

    • post_list.html

    • post_detail.html

    • post_form.html (común para CreateView y UpdateView)

    • post_confirm_delete.html (DeleteView)


5. Cómo personalizar Create/Update/DeleteView

5.1 Control detallado del formulario con form_class

class PostCreateView(CreateView):
    model = Post
    form_class = PostForm  # Especificar ModelForm
    ...

En PostForm, puedes establecer validación de campos o especificar widgets de manera detallada, lo que permite un manejo de formularios más flexible.

5.2 Redirección dinámica con get_success_url()

def get_success_url(self):
    # Ejemplo: redirigir a la página de detalle usando el pk del nuevo Post
    return reverse_lazy('post_detail', kwargs={'pk': self.object.pk})

self.object se refiere a la instancia del modelo que se ha procesado actualmente en Create/Update.

5.3 Control de acceso y adición de Mixin

  • Puedes combinarlo con LoginRequiredMixin para permitir que solo los usuarios logueados puedan crear/modificar/eliminar objetos.

  • Si deseas gestionar permisos de manera más detallada, considera PermissionRequiredMixin o UserPassesTestMixin.


6. Comparación con FBV

Funcionalidad FBV (vistas basadas en funciones) Create/Update/DeleteView (vistas basadas en clases)
Creación (Create) request.method == 'POST' condicional, definición directa de ModelForm, lógica de guardado escrita manualmente CreateView: al heredar, la creación de formularios, guardado y redirección se manejan automáticamente
Actualización (Update) Buscar el objeto existente y colocarlo en el formulario, la lógica de validación y guardado se repite durante el manejo de POST UpdateView: carga el objeto existente, modifica y guarda, automatizando la lógica
Eliminación (Delete) GET → renderizar la página de confirmación de eliminación, POST → manejar la eliminación, entrelazando toda la lógica en la función DeleteView: trae el objeto a eliminar y proporciona toda la lógica de manejo de eliminación y redirección
Legibilidad / Mantenimiento La lógica compleja puede hacer que el código se extienda, repitiendo lógica similar en varios lugares Redefiniendo métodos, puedes ajustar solo lo necesario y minimizar duplicados
Productividad en desarrollo (palabras clave principales) “Trabajo manual extenso, consume tiempo, duplicación de código” “Aumento de velocidad de desarrollo (ahorro de tiempo) y mejora en mantenibilidad (impulso en productividad)”

FBV vs CBV – Analogía con muebles de ensamblaje


7. Conclusión: Implementemos CRUD de manera rápida y clara a través de vistas genéricas!

Utilizando CreateView, UpdateView y DeleteView, puedes llevar a cabo las operaciones CRUD en Django con un código extremadamente claro e intuitivo.
Particularmente, la lógica de manejo de formularios duplicados y la redirección después de guardar datos se procesan automáticamente, permitiendo que los desarrolladores se centren principalmente en la “lógica de negocio” y en la “UI/UX”.

Si ahora comprendes ListView + DetailView + CreateView + UpdateView + DeleteView, podrás armar fácilmente una aplicación CRUD básica en Django!

En la siguiente publicación, abordaremos las TemplateView & RedirectView para explorar cómo automatizar el renderizado de páginas simples y el manejo de redirecciones.


Volver a ver publicaciones anteriores

  1. Explorando la serie de vistas basadas en clases (CBV) #1 - La razón por la que vamos de FBV a CBV y la mentalidad del desarrollador

  2. Explorando la serie de vistas basadas en clases (CBV) #2 - Entendiendo la estructura básica de las vistas de Django

  3. Explorando la serie de vistas basadas en clases (CBV) #3 - Simplificando el manejo de formularios con FormView

  4. Explorando la serie de vistas basadas en clases (CBV) #4 - Cómo utilizar ListView & DetailView


“Automatiza la implementación de CRUD utilizando las vistas genéricas de Django y mejora simultáneamente la velocidad de desarrollo del proyecto y la calidad del código!”