¿Diferencia entre los métodos de anotación y agregado de Django?


113

Django QuerySettiene dos métodos annotatey aggregate. La documentación dice que:

A diferencia de aggregate (), annotate () no es una cláusula terminal. La salida de la cláusula annotate () es un QuerySet.

¿Existe alguna otra diferencia entre ellos? Si no es así, ¿por qué aggregateexiste?

Respuestas:


186

Me centraría en las consultas de ejemplo en lugar de su cita de la documentación. Aggregatecalcula valores para todo el conjunto de consultas. Annotatecalcula valores de resumen para cada elemento del conjunto de consultas.

Agregación

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

Devuelve un diccionario que contiene el precio medio de todos los libros del conjunto de consultas.

Anotación

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q es el conjunto de consultas de libros, pero cada libro se ha anotado con el número de autores.


¿Estoy en lo cierto en que .annotate()en un qs solo no llega a la base de datos, pero llamar q[0].num_authorssí? Supongo aggregateque siempre debe presionar la base de datos, ya que es una cláusula terminal.
alias51

@ alias51 está realmente relacionado con la pregunta original, así que no creo que los comentarios sobre una pregunta de hace ocho años sean el mejor lugar para preguntar. Si desea comprobar cuándo se ejecutan las consultas, puede hacerloconnection.queries . Sugerencia: compruebe si es el book = q[0]o `book.num_authors` lo que provoca la consulta.
Alasdair

21

Esa es la principal diferencia, pero los agregados también funcionan a una escala mayor que las anotaciones. Las anotaciones están intrínsecamente relacionadas con elementos individuales en un conjunto de consultas. Si ejecuta una Countanotación en algo así como un campo de muchos a muchos, obtendrá un recuento por separado para cada miembro del conjunto de consultas (como un atributo agregado). Sin embargo, si hiciera lo mismo con una agregación, intentaría contar todas las relaciones en cada miembro del conjunto de consultas, incluso las duplicadas, y devolverlas como un solo valor.


¿Estoy en lo cierto en que solo .annotate()en una qs no llega a la base de datos, pero llamando al resultado de una anotación como lo q[0].num_authorshace? Supongo aggregateque siempre debe presionar la base de datos, ya que es una cláusula terminal.
alias51

21

Agregar agregado genera valores de resultado (resumen) en todo un QuerySet. El agregado opera sobre el conjunto de filas para obtener un valor único del conjunto de filas (por ejemplo, la suma de todos los precios en el conjunto de filas). El agregado se aplica en todo el QuerySet y genera valores de resultado (resumen) en todo un QuerySet.

En modelo:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

En Shell:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

Anotar Anotar generar un resumen independiente para cada objeto en un QuerySet. (Podemos decir que iterar cada objeto en un QuerySet y aplicar la operación)

En modelo:

class Video(models.Model):
    name = models.CharField(max_length=52, verbose_name='Name')
    video = models.FileField(upload_to=document_path, verbose_name='Upload 
               video')
    created_by = models.ForeignKey(User, verbose_name='Created by', 
                       related_name="create_%(class)s")
    user_likes = models.ManyToManyField(UserProfile, null=True, 
                  blank=True, help_text='User can like once', 
                         verbose_name='Like by')

En vista:

videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)

A la vista, contará los me gusta de cada video.


¿ distinct=TruePor qué se requiere en el último ejemplo?
Yuriy Leonov

@YuriyLeonov distinto = Verdadero utilizado para que la operación se realice en un valor distinto. No está relacionado con la pregunta actual. Lo siento por eso En realidad lo he usado en mi código.
Vinay Kumar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.