Аннотирование запроса с помощью списка значений (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

Вернуться на верх