Buscar..


Introducción

Una expresión F () es una forma en que Django puede usar un objeto de Python para referirse al valor del campo del modelo o la columna anotada en la base de datos sin tener que extraer el valor en la memoria de Python. Esto permite a los desarrolladores evitar ciertas condiciones de carrera y también filtrar los resultados según los valores de campo del modelo.

Sintaxis

  • desde django.db.models import F

Evitando las condiciones de carrera.

Vea esta pregunta de preguntas y respuestas si no sabe cuáles son las condiciones de la raza.

El siguiente código puede estar sujeto a condiciones de carrera:

article = Article.objects.get(pk=69)
article.views_count += 1
article.save()

Si views_count es igual a 1337 , esto resultará en dicha consulta:

UPDATE app_article SET views_count = 1338 WHERE id=69

Si dos clientes acceden a este artículo al mismo tiempo, lo que puede suceder es que la segunda solicitud HTTP ejecute Article.objects.get(pk=69) antes de que el primero ejecute article.save() . Por lo tanto, ambas solicitudes tendrán views_count = 1337 , lo incrementarán y guardarán views_count = 1338 en la base de datos, mientras que en realidad debería ser 1339 .

Para arreglar esto, usa una expresión F() :

article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()

Esto, por otro lado, resultará en dicha consulta:

UPDATE app_article SET views_count = views_count + 1 WHERE id=69

Actualizando queryset a granel

Supongamos que queremos eliminar 2 upvotes de todos los artículos del autor con id 51 .
Hacer esto solo con Python ejecutaría N consultas (siendo N la cantidad de artículos en el conjunto de consultas):

for article in Article.objects.filter(author_id=51):
    article.upvotes -= 2
    article.save()
    # Note that there is a race condition here but this is not the focus
    # of this example.

¿Qué pasaría si en lugar de juntar todos los artículos en Python, hacer un bucle sobre ellos, disminuir los votos positivos y guardar cada uno actualizado en la base de datos, hubiera otra manera?
Usando una expresión F() , puede hacerlo en una consulta:

Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)

Que se puede traducir en la siguiente consulta SQL:

UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51

¿Por qué es esto mejor?

  • En lugar de Python haciendo el trabajo, pasamos la carga a la base de datos que se ajusta para realizar dichas consultas.
  • Reduce efectivamente el número de consultas de base de datos necesarias para lograr el resultado deseado.

Ejecutar operaciones aritméticas entre campos.

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.

  • Que el modelo sea:

    class MyModel(models.Model):
        int_1 = models.IntegerField()
        int_2 = models.IntegerField()
    
  • Ahora supongamos que queremos recuperar todos los objetos de la tabla MyModel int_2 campos int_1 e int_2 satisfacen esta ecuación: int_1 + int_2 >= 5 . Utilizando annotate() y filter() obtenemos:

    result = MyModel.objects.annotate(
                 diff=F(int_1) + F(int_2)
             ).filter(diff__gte=5)
    

    result ahora contiene todos los objetos antes mencionados.

Aunque el ejemplo utiliza campos Integer , este método funcionará en todos los campos en los que se pueda aplicar una operación aritmética.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow