Django ORM – Примеры с несколькими таблицами (агрегация и групповые запросы)
Агрегатные запросы (aggregate)
Функции агрегатных запросов выполняют вычисления над набором значений и возвращают одно значение.
Перед использованием агрегатных запросов в Django необходимо сначала импортировать Avg, Max, Min, Count, Sum (с заглавной буквы) из django.db.models.
from django.db.models import Avg,Max,Min,Count,Sum # 引入函数
Возвращаемое значение агрегатного запроса имеет тип словаря.
Функция aggregate() является терминальной клаузой для QuerySet, формирует сводное значение, эквивалентна count().
После использования aggregate() тип данных становится словарём, и вы больше не можете использовать некоторые API типа данных QuerySet.
Тип данных даты (DateField) может использовать Max и Min.
В возвращаемом словаре: имя ключа по умолчанию — (имя атрибута плюс __ и имя агрегатной функции), а значение — вычисленное агрегированное значение.
Если вы хотите настроить имя ключа в возвращаемом словаре, можно задать псевдоним:
aggregate(别名 = 聚合函数名("属性名称"))
Вычислите среднюю цену всех книг:
Пример
...
res = models.Book.objects.aggregate(Avg("price"))
print(res, type(res))
...

Вычислите общее количество всех книг, самую высокую цену и самую низкую цену:
Пример
print(res,type(res)

Групповые запросы (annotate)
Групповые запросы обычно используют агрегатные функции, поэтому перед их использованием нужно импортировать Avg, Max, Min, Count, Sum (с заглавной буквы) из django.db.models.
from django.db.models import Avg,Max,Min,Count,Sum # 引入函数
Возвращаемое значение:
- После группировки, если использовать values для получения значений, возвращаемое значение — это тип данных QuerySet, содержащий словари.
- После группировки, если использовать values_list для получения значений, возвращаемое значение — это тип данных QuerySet, содержащий кортежи.
LIMIT в MySQL эквивалентен срезу типа данных QuerySet в ORM.
Примечание:
Поместите агрегатные функции внутрь annotate.
-
Поместите values или values_list перед annotate:values или values_list определяет, по каким полям группировать, а annotate выполняет группировку.
-
values или values_list размещены после annotate:annotate означает группировку непосредственно по pk текущей таблицы; values или values_list указывает, какие поля запрашивать, и вам нужно задать псевдонимы для агрегатных функций в annotate, затем указать эти псевдонимы в values или values_list.
Подготовьте данные и создайте модели
models.py
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8, decimal_places=2)
dep = models.CharField(max_length=32)
province = models.CharField(max_length=32)
class Emps(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8, decimal_places=2)
dep = models.ForeignKey("Dep", on_delete=models.CASCADE)
province = models.CharField(max_length=32)
class Dep(models.Model):
title = models.CharField(max_length=32)
Данные:
Выполните в командной строке MySQL:
Вычислите самую низкую цену книги для каждого издателя:
Пример
print(res)
Следующий вывод можно увидеть в командной строке:
<QuerySet [{'name': 'Example出版社', 'in_price': Decimal('100.00')}, {'name': '明教出版社', 'in_price': Decimal('300.00')}]>

Подсчитайте количество авторов для каждой книги:
Пример
print(res)
<QuerySet [{'title': 'Example', 'c': 1}, {'title': '吸星大法', 'c': 1}, {'title': '冲灵剑法', 'c': 1}]>

Подсчитайте количество авторов для каждой книги, название которой начинается с "dish":
Пример
print(res)

Подсчитайте названия книг с более чем одним автором:
Пример
print(res)
<QuerySet [{'title': 'Example', 'c': 1}, {'title': '吸星大法', 'c': 1}, {'title': '冲灵剑法', 'c': 1}]>

Отсортируйте QuerySet по убыванию в соответствии с количеством авторов каждой книги:
Пример
print(res)

Запросите общую стоимость книг, опубликованных каждым автором:
Пример
print(res)

Запрос F()
Экземпляр F() может ссылаться на поля в запросе, чтобы сравнивать значения двух разных полей в одном и том же экземпляре модели.
Созданные ранее фильтры сравнивают значения полей только с константой. Если вы хотите сравнить значения двух полей, нужно использовать F().
Перед использованием необходимо сначала импортировать F из django.db.models.
from django.db.models import F
Использование:
F("字段名称")
F динамически получает значение поля объекта и может выполнять операции.
Django поддерживает операции сложения, вычитания, умножения, деления и взятия по модулю между объектами F() и между объектами F() и константами.
В операции обновления также можно использовать функцию F().
Запросить людей, у которых зарплата больше их возраста:
Пример
...
book=models.Emp.objects.filter(salary__gt=F("age")).values("name","age")
...

Увеличить цену каждой книги на 100 yuan:
Пример
print(res)

Q() запрос
Перед использованием сначала импортируйте Q из django.db.models:from django.db.models import Q
Использование:
Q(条件判断)
Например:
Q(title__startswith="菜")
Множественные условия в ранее построенных фильтрах все связаны с помощью AND. Если вам нужно выполнять более сложные запросы (например, операторы OR), вы можете использовать Q.
Объекты Q можно комбинировать с помощью операторов &, |, ~ (AND, OR, NOT).
Приоритет от высокого к низкому: ~, &, |.
Можно смешивать объекты Q и именованные аргументы. Объекты Q и именованные аргументы объединяются с помощью "and" (т.е. запятые рассматриваются как AND), но объекты Q должны быть размещены перед всеми именованными аргументами.
Запросить названия и цены книг, цена которых больше 350 или название которых начинается с "dish".
from django.db.models import QПример
res=models.Book.objects.filter(Q(price__gt=350)|Q(title__startswith="dish")).values("title","price")
print(res)
...

Запросить книги, название которых заканчивается на "dish" или которые не выпущены в октябре 2010 года:
Пример
print(res)

Запросить книги с датой публикации в 2004 или 1999 году и названием, содержащим "dish".
Смешивайте объекты Q и именованные аргументы; объекты Q должны идти перед всеми именованными аргументами:
Пример
print(res)
