Problem
When I add an annotation based on the reverse field, then a double "LEFT OUTER JOIN" appears in the SQL result. As a result, the sum annotation is considered incorrect (duplicated depending on the number of back annotations)
How to make sum annotation correct?
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"
Models
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
)
Views
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__'