Как использовать prefetch_related у raw запроса django orm?
Дано:
models.py:
class Service(models.Model): # Продукт
name = models.CharField(max_length=1024)
class Client(models.Model): # Клиент
name = models.CharField(max_length=1024, blank=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='clients')
class Sale(models.Model): # Корзина покупок
client = models.ForeignKey(Client, on_delete=models.SET_NULL, related_name='purchases')
date = models.DateTimeField(auto_now_add=True)
class SoldService(models.Model): # Покупка (Продукт + Цена)
sale = models.ForeignKey(Sale, on_delete=models.CASCADE, related_name='services')
service = models.ForeignKey(Service, on_delete=models.PROTECT, related_name='sold')
price = models.DecimalField(max_digits=10, decimal_places=2)
views.py:
# Выбираю клиентов купивших определенный продукт и их последнюю соответсвующую корзину + её сумму
clients = Client.objects.raw('''
select distinct on (1) client.id,
client.name,
sale.date as sale_date,
sale.id as sale_id,
sum(sold_s.price) over (partition by sale.id) as sale_total
from accountant_client as client
join accountant_sale as sale on client.id = sale.client_id
join accountant_soldservice as sold_s on sale.id = sold_s.sale_id
join accountant_service as service on sold_s.service_id = service.id
where service.name like %(q)s
and client.company_id=%(company)s
order by 1, sale_date desc
''', {'q': f'%{q}%', 'company': request.user.company.id})
Для каждого клиента в запросе выбирается корзина покупок. Мне нужно вывести всех клиентов с подробной информацией о их соответсвующих покупках
Типо как-то так, но чтобы это не вызывало лишних запросов к бд:
for client in clients:
result.append({
'client': client.name,
'sale_total': client.sale_total,
'sale_services': Sale.objects.get(pk=client.sale_id).services.all().values('service__name')
})
Моё решение такое:
sales = Sale.objects.filter(id__in=[client.sale_id for client in clients]).prefetch_related('services__service').order_by('-date')
for client, sale in zip(clients, sales):
result.append({
'sale_services': sale.services.all().values('service__name')
...
Но решение с двумя списками выглядит не очень, оно может скрывать ошибки. Возможно ли к списку clients подтянуть всю информацию о корзине покупок не делая доп. запросов к бд?