values()和annotate()组合成group by 时,必须values再前,annotate在后,顺序不同则不起效果


values()

Ordinarily, annotations are generated on a per-object basis - an annotatedQuerySet will return one result for each object in the originalQuerySet. However, when a values() clause is used to constrain thecolumns that are returned in the result set, the method for evaluatingannotations is slightly different. Instead of returning an annotated resultfor each result in the original QuerySet, the original results aregrouped according to the unique combinations of the fields specified in thevalues() clause. An annotation is then provided for each unique group;the annotation is computed over all members of the group.

For example, consider an author query that attempts to find out the averagerating of books written by each author:

>>> Author.objects.annotate(average_rating=Avg('book__rating'))

This will return one result for each author in the database, annotated withtheir average book rating.

However, the result will be slightly different if you use a values() clause:

>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))

In this example, the authors will be grouped by name, so you will only getan annotated result for each unique author name. This means if you havetwo authors with the same name, their results will be merged into a singleresult in the output of the query; the average will be computed as theaverage over the books written by both authors.

Order of annotate() and values() clauses

As with the filter() clause, the order in which annotate() andvalues() clauses are applied to a query is significant. If thevalues() clause precedes the annotate(), the annotation will becomputed using the grouping described by the values() clause.

However, if the annotate() clause precedes the values() clause,the annotations will be generated over the entire query set. In this case,the values() clause only constrains the fields that are generated onoutput.

For example, if we reverse the order of the values() and annotate()clause from our previous example:

>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rating')

This will now yield one unique result for each author; however, onlythe author’s name and the average_rating annotation will be returnedin the output data.

You should also note that average_rating has been explicitly includedin the list of values to be returned. This is required because of theordering of the values() and annotate() clause.

If the values() clause precedes the annotate() clause, any annotationswill be automatically added to the result set. However, if the values()clause is applied after the annotate() clause, you need to explicitlyinclude the aggregate column.





猜你喜欢

转载自blog.csdn.net/qq_27361945/article/details/80091726