Cómo sobreescribir el método save() en Django

Cómo sobreescribir el método save() en Django
Photo by Ranmali Kirinde / Unsplash

En uno de los indicadores que desarrollamos necesitábamos medir el tiempo que tardaba nuestro producto en distribuirse desde una subdelegación hasta un Centro de Atención a Clientes (MAC).

Para cada envío registrábamos la siguiente información:

  • identificador del sitio;
  • fecha de corte;
  • lote de producción;
  • fecha y hora de recepción en la subdelegación; y
  • fecha y hora de recepción en el Centro de Atención.

A partir de esos datos necesitábamos calcular el tiempo transcurrido entre ambos eventos.

Aunque este cálculo podría realizarse cada vez que consultáramos la información, preferí hacerlo únicamente al momento de guardar el registro. De esa manera el valor quedaría almacenado en la base de datos y podría utilizarse posteriormente en reportes, consultas o indicadores sin necesidad de recalcularlo continuamente.

La forma más sencilla de conseguirlo es sobreescribiendo el método save() del modelo.

Nuestro modelo

El modelo utilizado para almacenar la información es el siguiente:

class Distribucion (models.Model):
    mac           = models.CharField (max_length = 6)
    fecha_corte   = models.DateField (default=timezone.now)
    lote          = models.CharField (max_length = 13)
    recibidoVRD   = models.DateTimeField ()
    disponibleMAC = models.DateTimeField ()
    diferencia    = models.IntegerField ()

    def __unicode__ (self):
        return "%s - %s - %s" % (self.mac, self.lote, self.fecha_corte)

El campo que nos interesa es diferencia, ya que almacenará el tiempo transcurrido entre la recepción en la subdelegación y la disponibilidad del producto en el Centro de Atención.

Sobreescribiendo save()

Django ejecuta el método save() cada vez que un objeto es creado o actualizado.

Si redefinimos ese método podremos realizar cualquier cálculo previo antes de que el registro sea almacenado en la base de datos.

En este caso únicamente calculamos la diferencia entre las dos fechas y guardamos el resultado en segundos.

def save(self):
    difFecha = self.disponibleMAC - self.recibidoVRD
    self.diferencia = difFecha.seconds
    super (Distribucion, self).save()

La primera línea obtiene un objeto que representa el tiempo transcurrido entre ambas fechas.

difFecha = self.disponibleMAC - self.recibidoVRD

A continuación almacenamos el número de segundos transcurridos en nuestro campo diferencia.

self.diferencia = difFecha.seconds

Finalmente llamamos al método save() de la clase base para que Django continúe con el proceso normal de almacenamiento.

super (Distribucion, self).save()

Este último paso es indispensable. Si omitimos la llamada a super(), el objeto nunca será guardado en la base de datos.

Ventajas de este enfoque

Al colocar el cálculo dentro del modelo evitamos repetir la misma lógica en cada vista que cree o modifique registros.

No importa si el objeto se crea desde una vista, desde el administrador de Django o desde un script de importación: siempre que se invoque save() el valor de diferencia será recalculado antes de almacenarse.

Además, la lógica relacionada con los datos permanece junto al propio modelo, lo que hace más sencillo mantener el código conforme la aplicación crece.

Una vez almacenado el número de segundos, la presentación queda completamente desacoplada. En las vistas o en las plantillas podemos convertir ese valor a horas, minutos o cualquier otro formato que resulte más conveniente para el usuario, sin necesidad de volver a calcular la diferencia entre las fechas.