Django: Como usar UpdateView con django-betterforms

Django: Como usar UpdateView con django-betterforms

Siguiendo el post anterior, ahora les mostraré cómo actualizar los registros, verán que fácil es y sin morir en el intento.

Tabla de contenido

  1. Primer paso con UpdateView
  2. Modificamos el archivo urls.py
  3. Simplificando nuestro código

Primer paso con UpdateView

Como bien sabemos la clase UpdateView pide propiedades obligatorias para trabajar, pero nosotros proporcionaremos lo que ya trabajamos con CreateView. Así que en el mismo archivo views.py escribiremos una nueva clase con lo siguiente.

class EmpleadoUpdateView(UpdateView):
    model = Empleado
    form_class = EmpleadoPersonaModelForm
    template_name = 'formulario.html'
    
    def get_form_kwargs(self):
        kwargs = super(EmpleadoUpdateView, self).get_form_kwargs()

        kwargs.update(instance={
            'persona': self.object.persona,
            'empleado': self.object
        })
        return kwargs

Aquí casi está todo igual al CreateView excepto el método get_form_kwargs. Éste lo que hace es instanciar nuestro registro empleado que venga desde parámetro de url si el id es 1,2... En self.object está la instancia empleado y lo que hacemos es asignárselo por separado a cada formulario para que se vean rellenados los campos en la vista html.

Agregamos un método más... seguro que ya lo habías visto antes....

# Metodo de la clase EmpleadoUpdateView
def form_valid(self, form):
    persona = form['persona'].save()
    empleado = form['empleado'].save(commit=False)
    empleado.persona = persona
    empleado.save()
    return HttpResponseRedirect(reverse('success'))

Resulta familiar verdad? Por supuesto que es el mismo método form_valid que agregamos en el formulario de creación. No se preocupen lo cambiaremos más adelante para simplificar nuestro código.


Modificamos el archivo urls.py

Éste archivo es el que está dentro de la app catálogos así que lo abrimos y debemos tener éste código tal cual.

from django.urls import path, re_path
from .views import EmpleadoCreateView, SuccessView, EmpleadoUpdateView


urlpatterns = [
    path('', EmpleadoCreateView.as_view(), name='index'),
    path('actualizar/<int:pk>/', EmpleadoUpdateView.as_view(), name='actualizar'),
    path('success/', SuccessView.as_view(), name='success'),
]

Ya podríamos visitar la url http://localhost:8000/actualizar/1/ Pero no desesperéis. ¡Que falta algo más!


Simplificando nuestro código

Ya casi terminamos no se preocupen, que haremos una serie de correcciones para que quede ya finalizado.

Simplificamos nuestro código quitando los métodos form_valid de las clases. Entonces nos vamos al archivo forms.py y agreguemos un método save, observen el resultado final:

from django.forms import ModelForm

from betterforms.multiform import MultiModelForm

from .models import Persona, Empleado


class PersonaModelForm(ModelForm):
    class Meta:
        model = Persona
        fields = '__all__'


class EmpleadoModelForm(ModelForm):
    class Meta:
        model = Empleado
        fields = ['categoria', 'salario']


class EmpleadoPersonaModelForm(MultiModelForm):
    form_classes = {
        'persona': PersonaModelForm,
        'empleado': EmpleadoModelForm,
    }

    def save(self, commit=True):
        objects = super(EmpleadoPersonaModelForm, self).save(commit=False)

        if commit:
            persona = objects['persona']
            persona.save()
            empleado = objects['empleado']
            empleado.persona = persona
            empleado.save()

        return objects

Ya con el método save nos funciona para las dos acciones, crear y modificar. Y por último, la definitiva, actualizamos los archivos html correspondiente con su texto para reutilizarlos.

formulario.html

<h1>Empleado</h1>

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Guardar">
</form>

success.html

<h1>El empleado ha sido guardado!</h1>


Bien! Con ésto terminamos ésta guía, mira el código fuente aquí y no olvides suscribirte.

Hasta la próxima. Bendiciones!