Аннотирование запроса с помощью списка значений (values_list), использование внешнего ключа и много-ко-многим в Django
У меня есть операция на django, которую я выполняю в 2 этапа, но я хотел бы узнать, есть ли способ сделать это с помощью одного запроса к базе данных. Скажем, у меня есть такие модели:
class Budget(models.Model):
...
class Company(models.Model):
budgets = models.ManyToManyField(
Budget, related_name="companies"
)
class Employee(models.Model):
company = models.ForeignKey(
Company, on_delete=models.CASCADE, related_name="employees"
)
Теперь я хочу получить сотрудника и найти идентификаторы бюджетов, которые связаны с этим сотрудником, через компанию:
employee = Employee.objects.get(id=employee_id)
allowed_budgets = employee.company.budgets.values_list("id", flat=True)
Правильно ли я понимаю, что в этом случае выполняется 2 запроса к базе данных? Есть ли способ добавить allowed_budgets
в качестве аннотации к Employee
, чтобы выполнялся только один запрос?
employee = Employee.objects
.annotate(
allowed_budgets=# how do I get employee.company.budgets.values_list("id", flat=True) here?
)
.get(id=employee_id)
Большое спасибо!
Возможно, вы можете создать подкласс подзапроса, который изменяет выводимый им SQL. Подзапросы и аннотации - это мощные инструменты, которые предназначены для вложения и составления более сложных вычислений. Например:
from django.db.models import OuterRef, Subquery,Count
Employee.objects.annotate(
count=Subquery(
Budget.objects
.filter(budgets=OuterRef('id'))
.values('budgets')
.annotate(count=Count('id'))
.values('count')
)
)
Для PostgreSQL:
from django.contrib.postgres.aggregates import ArrayAgg, StringAgg
Employee.objects.annotate(
cls=Subquery(
Budgets.objects.filter(id=OuterRef('id')).values('id')\
.annotate(budgets=ArrayAgg('budgets')).values('budgets')
)
)
Дополнительная информация: https://django.readthedocs.io/en/stable/ref/models/expressions.html