Cómo ejecutar operaciones aritméticas entre campos de modelo en django

Prólogo:

Esta es una pregunta que surge a menudo en SO:

  • Restar dos columnas anotadas
  • Consulta de Django con aritmética simple entre los campos del modelo y comparación con el campo de otro modelo
  • Agregación de Django: Suma de la multiplicación de dos campos

Y también se puede aplicar aquí:

  • Expresión de Django F en objetos de fecha y hora

He compuesto un ejemplo en la Documentación SO, pero como la Documentación se cerrará el 8 de agosto de 2017, seguiré la sugerencia de esta meta-respuesta ampliamente comentada y comentada, y transformaré mi ejemplo en una publicación auto contestada.

Por supuesto, también me encantaría ver cualquier enfoque diferente.


Pregunta:

Supongamos el siguiente modelo:

class MyModel(models.Model): number_1 = models.IntegerField() number_2 = models.IntegerField() date_1 = models.DateTimeField() date_2 = models.DateTimeField() 

¿Cómo puedo ejecutar operaciones aritméticas entre los campos de este modelo?

Por ejemplo, ¿cómo puedo encontrar:

  • ¿El producto de number_1 y number_2 de un objeto MyModel?
  • ¿Cómo filtrar elementos donde date_2 es 10 o más días anterior a date_1 ?

F() expresiones F() se pueden usar para ejecutar operaciones aritméticas ( + , - , * etc.) entre los campos del modelo, para definir una búsqueda / conexión algebraica entre ellos.

Un objeto F() representa el valor de un campo de modelo o columna anotada. Permite hacer referencia a los valores de campo del modelo y realizar operaciones de base de datos usándolos sin tener que sacarlos de la base de datos a la memoria de Python.

abordemos los problemas entonces:

  • El producto de dos campos:

     result = MyModel.objects.all().annotate(prod=F('number_1') * F('number_2')) 

    Ahora, cada elemento del result tiene una columna adicional llamada ‘prod’ que contiene el producto de number_1 y number_2 de cada elemento, respectivamente.

  • Filtrar por diferencia de día:

     from datetime import timedelta result = MyModel.objects.all().annotate( delta=F('date_2') - F('date_1') ).filter(delta__gte=timedelta(days=10)) 

    Ahora los elementos en el result son los de MyModel cuya date_2 es 10 o más días más antigua que date_1 . Estos elementos tienen una nueva columna llamada delta con esa diferencia.

  • Un caso diferente:

    Incluso podemos usar expresiones F() para realizar operaciones aritméticas en columnas anotadas de la siguiente manera:

     result = MyModel.objects.all() .annotate(sum_1=Sum('number_1')) .annotate(sum_2=Sum('number_2')) .annotate(sum_diff=F('sum_2') - F('sum_1'))