РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
70 of 818 menu

Метод annotate

Метод annotate применяется к QuerySet и возвращает новый QuerySet, каждый объект которого дополнен новым атрибутом - аннотацией. В качестве аргументов метод принимает именованные параметры, где имя становится ключом аннотации, а значение - это выражение для вычисления значения. Это может быть агрегатная функция (Count, Sum, Avg и другие), выражение F или любая другая функция базы данных.

Синтаксис

Model.objects.annotate(**annotations)

Пример . С Count

Посчитаем количество комментариев к каждой статье. Для этого используем агрегатную функцию Count, передав в неё имя связанного поля:

from myapp.models import Article from django.db.models import Count articles_with_comments = Article.objects.annotate( comments_count=Count('comments') ) for article in articles_with_comments: print(f"{article.title}: {article.comments_count} comments")

Результат выполнения кода:

"Article 1: 5 comments" "Article 2: 2 comments" "Article 3: 0 comments"

Пример . С Sum

Рассчитаем общую сумму всех заказов для каждого пользователя. Используем аннотацию с функцией Sum:

from myapp.models import User, Order from django.db.models import Sum users_with_total = User.objects.annotate( total_orders_amount=Sum('orders__amount') ) for user in users_with_total: print(f"{user.username}: ${user.total_orders_amount or 0}")

Результат выполнения кода:

"john: $1500" "jane: $3200" "bob: $0"

Пример . С Avg

Вычислим средний рейтинг для каждого продукта. Для пустых наборов значений результат будет равен None, поэтому можно использовать Coalesce для замены:

from myapp.models import Product, Review from django.db.models import Avg, Coalesce, Value from django.db.models.functions import Coalesce products_with_rating = Product.objects.annotate( avg_rating=Coalesce(Avg('reviews__rating'), Value(0)) ) for product in products_with_rating: print(f"{product.name}: {product.avg_rating:.1f}")

Результат выполнения кода:

"Laptop: 4.5" "Mouse: 4.8" "Keyboard: 0.0"

Пример . С F-выражениями

Создадим аннотацию, которая вычисляет значение на основе других полей модели. Например, посчитаем итоговую цену с учётом скидки:

from myapp.models import Product from django.db.models import F, ExpressionWrapper, FloatField products_with_discount = Product.objects.annotate( price_with_discount=ExpressionWrapper( F('price') * (1 - F('discount') / 100), output_field=FloatField() ) ) for product in products_with_discount: print(f"{product.name}: ${product.price_with_discount:.2f}")

Результат выполнения кода:

"Laptop: $850.00" "Mouse: $24.00" "Keyboard: $45.00"

Пример . С условиями в аннотации

Добавим аннотацию, которая показывает статус товара на основе количества на складе. Используем Case и When:

from myapp.models import Product from django.db.models import Case, When, Value, IntegerField products_with_status = Product.objects.annotate( stock_status=Case( When(stock_quantity__gte=100, then=Value('Много')), When(stock_quantity__gte=50, then=Value('Достаточно')), When(stock_quantity__gt=0, then=Value('Мало')), default=Value('Нет в наличии'), output_field=IntegerField() ) ) for product in products_with_status: print(f"{product.name}: {product.stock_status}")

Результат выполнения кода:

"Laptop: Много" "Mouse: Достаточно" "Keyboard: Мало"

Смотрите также

  • метод aggregate,
    который возвращает итоговые агрегированные значения
  • метод alias,
    который создаёт аннотации без добавления их в результаты запроса
  • класс Count,
    который используется для подсчёта количества записей
  • класс Sum,
    который используется для суммирования значений поля
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить