I need to make an API with this body structure for graph with multiple lines:
[
{
"title": "Test title",
"dots": [
{
"date": "2023-03-03",
"sum_weight": 5000
},
{
"date": "2023-03-06",
"sum_weight": 1500
}
]
}
]
But I have a problem with Prefetch, since it's not possible to use .values() to do group_by date
during query. Right now my ungrouped API looks like this:
[
{
"title": "Test title",
"dots": [
{
"date": "2023-03-03",
"sum_weight": 5000
},
{
"date": "2023-03-06",
"sum_weight": 500
},
{
"date": "2023-03-06",
"sum_weight": 1000
}
]
}
]
My code right now:
Query:
groups = Group.objects.prefetch_related(
Prefetch("facts",
queryset=Facts.objects.order_by("date").annotate(sum_weight=Sum("weight")))
)
Serializers:
class GraphDot(serializers.ModelSerializer):
sum_weight = serializers.SerializerMethodField()
def get_sum_weight(self, obj):
if not hasattr(obj, 'sum_weight'):
return 0
return obj.sum_weight
class Meta:
model = Facts
fields = read_only_fields = ("date", "sum_weight",)
class FoodGraphSerializer(serializers.ModelSerializer):
dots = GraphDot(many=True, source="facts")
class Meta:
model = Group
fields = read_only_fields = ("title", "dots")
Is there any way to make a query that is grouped by date
so my sum_weight
annotation is summed within it?
Thanks to @PTomasz comment, I've added Window expression to my query.
So the final query looks like this:
groups = Group.objects.prefetch_related(
Prefetch("facts",
queryset=Facts.objects.annotate(
sum_weight=Window(
expression=Sum('weight'),
partition_by=[F('date')],
order_by=OrderBy(F('date'))))
.distinct("date"))
)
Without .distinct("date")
objects were still duplicating, but with right sum_weight
(both had 1500).
With it everyting is good.