Вложение сериализатора по годам, затем по месяцам

class Transactions(models.Model):
    id = models.CharField(max_length=100, primary_key=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    date = models.DateField()
    watch = models.CharField(max_length=100)
    purchase_price = models.IntegerField()
    sale_price = models.IntegerField()

В моей модели Transactions есть поле даты, цена покупки и цена_продажи.

@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def profit_chart(request):
    current_year = datetime.now().year
    queryset = Transactions.objects.filter(date__year=current_year).values(month=ExtractMonth('date'),
                                                                           year=ExtractYear('date')).annotate(
        profit=Sum(F('sale_price')) - Sum(F('purchase_price'))).order_by('month')
    serializer = ProfitChartSerializer(queryset, many=True)
    return Response(serializer.data, status=status.HTTP_200_OK)

Мое представление сортирует транзакции по текущему году и месяцу, а затем вычисляет прибыль за этот месяц.

class ProfitChartSerializer(serializers.ModelSerializer):
    year = serializers.IntegerField()
    month = serializers.IntegerField()
    profit = serializers.IntegerField()

    class Meta:
        model = Transactions
        fields = ['year', 'month', 'profit']

Ответ, который я получил от DRF, приведен ниже.

[
    {
        "year": 2024,
        "month": 8,
        "profit": 5000
    }
]

Вопрос, который я пытаюсь выяснить, заключается в том, как я могу манипулировать приведенным выше ответом, чтобы он выглядел так, как показано ниже.

[
    year:  2024
    data: {
        month: 8
        profit: 5000
    }
]

Я не думаю, что это имеет большой смысл. Действительно, вы фильтруете по году:

queryset = Transactions.objects.filter(date__year=current_year)

поэтому год всех возвращенных записей будет одинаковым.

Однако вы можете настроить сериализатор с помощью:

class PartialChartSerializer(serializers.ModelSerializer):
    month = serializers.IntegerSerializer()
    profit = serializers.IntegerField()

    class Meta:
        model = Transactions
        fields = ['month', 'profit']


class ProfitChartSerializer(serializers.Serializer):
    year = serializers.IntegerField()
    data = PartialChartSerializer(many=True)

и передаем элементы в сериализатор в виде:

from itertools import groupby
from operator import itemgetter


@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def profit_chart(request):
    queryset = (
        Transactions.objects.values(
            month=ExtractMonth('date'), year=ExtractYear('date')
        )
        .annotate(profit=Sum(F('sale_price')) - Sum(F('purchase_price')))
        .order_by('month')
    )
    serializer = ProfitChartSerializer(
        [
            {'year': k, 'data': list(vs)}
            for k, vs in groupby(queryset, itemgetter('year'))
        ],
        many=True,
    )
    return Response(serializer.data, status=status.HTTP_200_OK)

Note: Normally a Django model is given a singular name [django-antipatterns], so Transaction instead of Transactions.

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