Django ORM дублирует LEFT OUTER JOIN в SQL при аннотировании
Проблема
Когда я добавляю аннотацию на основе обратного поля, то в результате SQL появляется двойной "LEFT OUTER JOIN". В результате аннотация суммы считается неправильной (дублируется в зависимости от количества обратных аннотаций)
Как сделать аннотацию суммы правильной?
Django 4.0.3
Python 3.10
Result SQL
SELECT
"frontend_book"."id",
"frontend_book"."title",
"frontend_book"."author_id",
COALESCE(
SUM("frontend_sell"."price"),
0
) AS "total_profit_author",
COALESCE(
SUM(T4."price"),
0
) AS "total_profit_resolver"
FROM
"frontend_book"
INNER JOIN "frontend_human" ON (
"frontend_book"."author_id" = "frontend_human"."id"
)
LEFT OUTER JOIN "frontend_sell" ON (
"frontend_human"."id" = "frontend_sell"."author_id"
)
LEFT OUTER JOIN "frontend_sell" T4 ON ( <----- HERE
"frontend_human"."id" = T4."resolver_id"
)
GROUP BY
"frontend_book"."id"
Модели
class Human(models.Model):
name = models.CharField(
'Name',
max_length=200,
blank=True,
)
class Book(models.Model):
title = models.CharField(
'Title',
max_length=200,
blank=True,
)
author = models.ForeignKey(
Human,
verbose_name='author',
related_name='books',
on_delete=models.CASCADE,
)
class Sell(models.Model):
author = models.ForeignKey(
Human,
verbose_name='Author',
related_name='author_sells',
on_delete=models.CASCADE,
)
resolver = models.ForeignKey(
Human,
verbose_name='Resolver',
related_name='resolver_sells',
on_delete=models.CASCADE,
)
price = models.FloatField(
'Price',
default=0,
blank=True
)
Виды
from rest_framework.response import Response
from rest_framework.views import APIView
from backend.api.frontend.models import Book
from django.db.models import Sum, FloatField
from .serializers import BookSerializer
class TestView(APIView):
def get(self, request):
qs = Book.objects.all()
qs = qs.annotate(
total_profit_author = Sum(
'author__author_sells__price',
output_field=FloatField(),
default=0,
),
total_profit_resolver = Sum(
'author__resolver_sells__price',
output_field=FloatField(),
default=0,
),
)
return Response({
"data": BookSerializer(qs, many=True).data,
})
Serializers
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
total_profit_author = serializers.FloatField(read_only=True)
total_profit_resolver = serializers.FloatField(read_only=True)
class Meta:
model = Book
fields = '__all__'
Отличный ответ https://stackoverflow.com/a/56619484/9477837
Django ORM problem (13 years old) https://code.djangoproject.com/ticket/10060