Рубрики
Без рубрики

¿Cuándo USAR Annotate Y Alverage En Django?

La Pantalla del Ordenador Iluminó Mi Rostro Lleno de desperación, Me Froté La Cabeza Con Desesperac … Теги с Джанго, Питоном, Испанским, Учебником.

La Pantalla del Ordenador Iluminó Mi Rostro Lleno de Desesperación, Me Froté La Cabeza Con Desesperación, Mientras Buscaba en Google: «Джанго Аннотат»; Una de las funciones del Orm Que no lograba ¿ Te Ha Pasado También?, Apuesto Que Sí. Ya Había Leído La Documentación Pero No Me Me Pareció Lo Sufocatedemente Clara Y, Para Colmo, La Confundía Frecuendemente Con Su Gemela Malvada: Aggregate. TRAS Haber Visaado Varias Preguntas de Stackoverflow Y Múltiples Блоги En Inglés Pude Enterderlas A Ambas. Estas Notas Son El Resultsado de Esa Búsqueda, ES La Esplicación Sobre Annotate Y Aghnacate de Django Que Mi Me Hubiera Gustado Leer Hace Años.

Учебник ESTE DA POR HECHO QUE CONOCES LO Básico Sobre El Orm de django, EN Caso de que Нет, Tengo EL infula en en libro gratuito en Mi Entrada Sobre. La Guia indexitiva de django.

Si Estás Aquí Porve Quier Quieres Mejorar El Rendimiento de Tu Alippión En Django, Tengo Una Serie de Consejos que Puedes Extrementar en Esta Entrada.

Препарация

PARA ESTE EJEMPLO VAMOS A CREAR PAR DE MOSTOROS FICTICIOS QUE USAREMOS PARA LOS EJEMPLOS:

# app/models.py
from django.db import models

class Seller(models.Model):
    name = models.CharField(max_length=150)

class Order(models.Model):
    seller = models.ForeignKey(Seller, related_name="orders", on_delete=models.PROTECT)
    total = models.DecimalField(max_digits=18, decimal_places=9)

TRAS Applicar LAS Migraciones, El Código Anterword Crará Dos Modelos: Presender (продавец) Y Pedido (заказ). ООН Pendeor Puede Tener Mouseos Pedidos. ООН Pedido соответствует Tiene Tiene un único Vendey y Tiene, expresado en números десятиленды.

Continuación Voy Crage Unos Cuantos Datos A Manera de Ejemplo. Tú PUEDES HACERLO EL EL admin de django o Directo en la base de detos.

Tabla Para Para Vende

1 Показывать
2 Lovecraft
3 Баркер

Tabla Para Pedido.

1 100 1
2 200 1
3 300 2
4 400 2
5 500 3
6 600 3

Antes de Hababar Sobre Annotate Y Совокупный Hay Que asegurarnoS de Saber Como Obtener La Consulta SQL Que Hará Django.

¿ Cómo ConventiR EN Queryset SQL?

Веробанемент Ya Conozcas El Orm de django y lo Hayas usado para hacer búsquedas en la base de datos. Перо наличия алгов-каутас Персонас Игнаран: ES Bosible Obtener La Consulta, Antes de que django La Procese y Ejecute, Impriendo La Propiedad Query de Nuestros Querysets.

ESA Consulta Debe Tener Asociada Una Consulta, EN Lenguaje SQL, Acceder acced accediendo la Propiedad Query.

print(Seller.objects.all().query)
SELECT "app_seller"."id", "app_seller"."name" FROM "app_seller"

Conocer La Consulta que realizará django nos ayuda entender que astá suciciendo tras elrm. ESTO Será de Utilidad Para Profundizar EN Аннотировать Отказ

Аннотизировать

¿POR Qué Usar Annotate?

Воображение Que queremos Mastrar En Una Plantilla de Django Cada Vende, Seguido De La Suma Del Total De Todos Sus Pedidos. La Aproximación Burda Sería Algo Parecido Esto

# app/models.py
# NO HAGAS ESTO, ES INEFICIENTE

class Seller(models.Model):
    name = models.CharField(max_length=150)

    def get_order_sum(self):
        total_sum = 0
        for order in self.orders.all():
            print(self.orders.all().query)
            # Puedes verlo en la terminal
            total_sum += order.total
        return total_sum

PARA MOSTRARLO EN CódiGo HTML, Усандо-эль-Система де Коллиллы, Llamaríamos al Método Una Vez Por Cada Elemento de Nuestra Lista de Vendedo.

{% for seller in sellers_list %}
  {{ seller.get_order_sum }}
{% endfor %}

Sin Usar Аннотировать EN Django Necesitaríamos un Query Para La Lista de Venesedores Y UNO Extry POR CADA VENDESOR, CUANDO SON 3 VENCEDORES, COMO AQUí, NO SHEAL SMALLA, PERO y Si Si Fueran 100 O 200 O Más? CADA PETTORYON VA SERU MUY COSTOSA EN TIEMPO Y Recursos.

Si Examinas Las Queries Verás una Query Diferente Para Cada Vende.

SELECT ••• FROM "app_seller"
# La consulta anterior es para obtener todos los vendedores
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '1'
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '2'
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '3'

Annotate Puede Repadir El Número de Consultas A La Base de Datos Y Con Ello Mejorar El Tiempo que Tarda Nuestro Servidor En Devolver Una Respuesta.

¿Cuándo Usar Annotate En Django?

Усамос Аннотировать CuAndo Queremos Hacer Una Anotación EN CADA OBJETO Queryset uv devuelva de un cerryset Отказ COMO Si Quisieramos Agregar Una Propiedad Extra CaDa Objeto de TU Queryset, Pero Directo Desde La Base de Datos.

En Django, Annotate CREA OA Anotación Para Cada Uno de los elementos de nuestro Queryset y devualve el butevensado como un comeryset.

from app.models import Seller
from django.db.models import Sum

sellers_with_orders_total = Seller.objects.annotate(orders_total = Sum('orders__total'))
print(sellers_with_orders_total.query)
SELECT "app_seller"."id", "app_seller"."name", CAST(SUM("app_order"."total") AS NUMERIC) AS "orders_total" FROM "app_seller" LEFT OUTER JOIN "app_order" ON ("app_seller"."id" = "app_order"."seller_id") GROUP BY "app_seller"."id", "app_seller"."name"

Mira La Consulta, Nos Devolverá Cada Linea de la Base de Datos (Presendor) Con Una Anotación Extra Llamada Orders_total o el Nombre que le Hayamos Asignado, que соответствует a la suma de los therees de sus questives.

EL MISMO BUSTORMADO Que Antes … ¡Pero en un solo запрос!

sellers_with_orders_total[0].orders_total
Decimal('300')
# Los pedidos asociados a Poe suman 300

También podriamos contarlos, en lugar de sumarlos.

from app.models import Seller
from django.db.models import Sum, Count

sellers_with_orders_count = Seller.objects.annotate(orders_count = Count('orders'))
print(sellers_with_orders_count.query)
SELECT "app_seller"."id", "app_seller"."name", COUNT("app_order"."id") AS "orders_count" FROM "app_seller" LEFT OUTER JOIN "app_order" ON ("app_seller"."id" = "app_order"."seller_id") GROUP BY "app_seller"."id", "app_seller"."name"

Ахора, CADA Elemento Del Queryset Poseerá una Propiedad llamada Orders_count , que al al conteo de los pedidos que tiene, en este caso cada uno de los venceores cuenta con dos pedidos.

sellers_with_orders_count[0].orders_count
2

Concatenar Connotate

COMO Mencioné Al Commaribied; Аннотировать девуэлью ООН запрос , пункт кабеля Podemos Concatenar Múltiples Annotate Para Una Sola Consulta A La Base de Datos.

from app.models import Seller
from django.db.models import Sum, Count

combined_querysets = Seller.objects.annotate(orders_count = Count('orders')).annotate(orders_total = Sum('orders__total'))
print(combined_querysets.query)
SELECT "app_seller"."id", "app_seller"."name", COUNT("app_order"."id") AS "orders_count", CAST(SUM("app_order"."total") AS NUMERIC) AS "orders_total" FROM "app_seller" LEFT OUTER JOIN "app_order" ON ("app_seller"."id" = "app_order"."seller_id") GROUP BY "app_seller"."id", "app_seller"."name"

Обсуждение Como Usamos El Doble Guión Bajo Para Acceder A La Propiedad “Total” Del objeto Заказ продавцов Desde, Como Harías en Custquier Queryset de django.

Ahora Cada Elemento Contiene Tanto El Conteo de Sus Pedidos, Como El Total De Estos, Todo En Una Sola Consulta A La Base de Datos.

combined_querysets[0].orders_total 
Decimal('300')
# El total de los pedidos de Poe suman 300
combined_querysets[0].orders_count 
2
# Poe tiene dos pedidos

EL Ошибка не может разрешить ключевое слово AL USAR Annotate

Si Combinas dos querysets y en uno de eellos обладает аннотатом USADO, отсутствует obtener los resultdos que esperas. Lo Передний окурр Порка Estás Intentando Unir Dos Querysets Con Campos Desiguales.

queryset_1 = Seller.objects.annotate(orders_count = Count('orders')).filter(name__startswith="Poe")
queryset_2 = Seller.objects.filter(name__startswith="Lovecraft")
# ERROR
results = queryset_2 & queryset_1
# django.core.exceptions.FieldError: Cannot resolve keyword 'orders_count' into field

PARA SolucioSar EL Flancea Deles Igualar Los Querysets, Para Que Ambos Posean Con El Campo Que Agrogastaste Connotate.

queryset_1 = Seller.objects.annotate(orders_count = Count('orders')).filter(name__startswith="Poe")
queryset_2 = Seller.objects.annotate(orders_count = Count('orders')).filter(name__startswith="Lovecraft")
# CORRECTO
results = queryset_1 & queryset_2

Otra Forma de Solucionarlo Sería Realizar La Unión Con El Queryset Con Annotate Primero

queryset_1 = Seller.objects.annotate(orders_count = Count('orders')).filter(name__startswith="Poe")
queryset_2 = Seller.objects.filter(name__startswith="Lovecraft")
# CORRECTO
results = queryset_1 & queryset_2

Совокупность

¿ Пара Qué Usar Aggregate?

Imagina Que Queremos Sabre El Total de Ascroutamente ToDos Los Pedidos, Para Procesarlo o Renderizarlo en una Plostilla Sportionermente. UNA APROXIMACINON Bastante Ingenua Sería Incluir El Siguiente Código Doctro de Una Función o Método.

from app.models import Seller

# NO HAGAS ESTO, ES INEFICIENTE
all_orders_total = 0
for seller in Seller.objects.all()
    for order in seller.orders.all()
        all_orders_total += order.total
        # ...
print(all_orders_total)
Decimal('2100.000000000')

El Pedazo de Código Ansiory Es Inefinede, Neevamente Estamos Consultando Múltiples Veces La Base de Datos y Procesando Información Con Python, Lo Cual Нет Эс Мало , Перо Генерал Уна База de ditos es luco más efinede.

SELECT ••• FROM "app_seller"
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '1'
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '2'
SELECT ••• FROM "app_order" WHERE "app_order"."seller_id" = '3'

EN Lugar de Usar Python Para Calcular EL TOTELE DE LOS PEDIDIDOS, PODRIAMOS DARLE Insruccciones A La Base DE DESOS PARA QUE LO CALLULY USANDO совокупность Отказ

¿ Cuándo Deberiamos USAR Aggregate?

Asamos Aggregate CuAndo Queremos Repense El Total De ООН Запрос ООН Solo Dato, Este Dato Puede Ser un Promedio, Una Sumatoria, ООН Valor Mínimo, Máximo и т. Д. Совокупные NOS Premate Procesarlo Directo Desde La Base DE DESOS, SIN QUE TENGAMOS QUE PRECESAR LOS DECOS CON PYTHON NOSOTROS MISMOS.

De acuerdo al o Anderior, Sería Удобно ReemPlazar El Código Ansiory Con El Siguiente Queryset. PodeMos Esceificar El Nombre Que Se Usará de llave en nuestro diccionario o dejar que django lo genere de manera automática. Sin Embargo, Para Este Ejemplo Lo Nombraremos sum_of_all_orders Отказ

Seller.objects.aggregate(sum_of_all_orders = Sum('orders__total'))
{'sum_of_all_orders': Decimal('2100')}
# El total sumado de todos los pedidos es 2100

Así mismo, en lugar de pedirle que nos sume, podriamos pedirle un promedio, o un conteo también, o uncer un Фильтр Previo al совокупность Отказ

total_orders = Seller.objects.aggregate(total_orders = Count('orders'))
total_orders 
{'total_orders': 6}
# Entre todos los vendedores tienen 6 pedidos 

Si Intentamos Obtener La Query de совокупность El Intérprprete de python nos devolverá Ошибка ООН Порка, Дифсеренсия de Аннотировать , совокупность devualve un diccionario нет никакого запроса ООН.

total_orders.query
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'dict' object has no attribute 'query'

De la misma manera podimos concatenar un Аннотировать Ун. совокупность , Siempre Y Cuando El Agvery Esté Al Final De La Concatenación Эсто Debido aque Совокупность нет Devualve Query un.

Además, совокупность Tiene Acceso A Anotaciones Las Anotaciones Que Agreguemos CADA Elemento Usando Аннотировать Отказ

from django.db.models import Avg

Seller.objects.annotate(orders_total = Sum('orders__total')).aggregate(Avg('orders_total'))
{'orders_total__avg': Decimal('700')}
# Poe 100+200=300
# Lovecraft 300+400=700
# Barker 500+600=1100
# (300+700+1100)/3 = 700

Обсуждение COMO Аннотировать Агрегар Orders_total CADA Elemento Del Queryset Y, Soormente, совокупность USA ESA Anotación Para Calcular El Promedio Usando AVG Отказ

Si Sabes Usar Correcte совокупность y Аннотировать Puedes Repadiir Bastante La Cantidad de queeries que se a a a la base de datos y con eello repuesta entre cada el tiempo de Respuesta entre Cada Petición.

Recuerda que si quieres profundizar aún Más en El Tema дебюс Леер La Documentaciónfiable de django.

Оригинал: “https://dev.to/silicosis/cuando-usar-annotate-y-aggregate-en-django-2gh4”