Django Rest Framework: сумма сериализаторов и полей - PullRequest
0 голосов
/ 21 января 2020

У меня проблемы с получением этого к работе .. У меня есть следующий сериализатор:

class OwnArbeitstagListSerializer(serializers.ModelSerializer):
    stundensumme = serializers.SerializerMethodField()
    class Meta:
        model = Arbeitstag
        ordering = ['-datum']
        fields = ('id', 'datum', 'in_abrechnung', 'stundensumme')
        depth=0

    def get_stundensumme(self, obj):
        return Stunden.objects.filter(arbeitstagid=obj.id).aggregate(Sum('stunden'))['stunden__sum']

.. возвращающий сумму отработанных часов в день (модель называется "рабочий день"). Это работает до сих пор. Теперь я хочу, чтобы ModelViewset возвращал список рабочих дней:

class OwnArbeitstagListViewSet(viewsets.ReadOnlyModelViewSet):
    filter_class = ArbeitstagListFilter
    filter_fields = ('datum',)
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter,)
    ordering =["-datum"]
    serializer_class = OwnArbeitstagListSerializer
    def get_queryset(self):
        return Arbeitstag.objects.filter(userid=self.request.user.id)

Видите ли, я фильтрую его по Пользователю и по дате (с помощью filterbackend). Но теперь я хочу иметь дополнительное поле, которое дает мне сумму сериализованного метода fieldfield "stundensumme". Это сумма суммы. И он должен только вычислять сумму отображаемых объектов (с примененным datefilter).

У меня проблемы, потому что (я предполагаю) Seriealizermethodfield рассчитывается только при сериализации, и я думаю, что уже поздно, чтобы получить значения для моей суммы. Я пробовал это, но он не может найти serializermethodfield "stundensumme", чтобы вычислить сумму:

class CustomPageNumberPagination(PageNumberPagination):
    def get_paginated_response(self, data, summe):
        return Response(OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('summe', summe),
            ('results', data)
        ]))


class OwnArbeitstagListViewSet(viewsets.ReadOnlyModelViewSet):
    pagination_class = CustomPageNumberPagination
    filter_class = ArbeitstagListFilter
    filter_fields = ('datum',)
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter,)
    ordering =["-datum"]
    serializer_class = OwnArbeitstagListSerializer
    def get_queryset(self):
        arbeitstag = Arbeitstag.objects.all().filter(userid=self.request.user.id)
        return arbeitstag
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        self.summe = queryset.aggregate(Sum('stundensumme'))['stundensumme__sum']
        return super().list(request, *args, **kwargs)
    def get_paginated_response(self, data):
        return self.paginator.get_paginated_response(data, self.summe)

1 Ответ

0 голосов
/ 23 января 2020

Если вы посмотрите на реализацию метода list(), вы обнаружите следующее:

    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Вы правы в своем предположении, что поле stundensumme получает только сериализацию, поэтому у вас есть два варианта:

  1. используйте anotate () и добавьте его в свое определение get_queryset(), чтобы у каждого объекта было это поле, и вам не нужно предоставлять реализацию для поле в сериализаторе, и вы просто добавите поле в атрибуте fields, как вы сделали

  2. в get_paginated_response() внесите сумму на data, так как это список, возвращаемый сериализатором, чтобы вы могли легко манипулировать им, например:

    def get_summe (self, data):

    sum = 0
    for item in data:
        sum += item['stundensumme']
    return
    

и просто использовать его

def get_paginated_response(self, data):
    return Response(OrderedDict([
        ('count', self.page.paginator.count),
        ('next', self.get_next_link()),
        ('previous', self.get_previous_link()),
        ('summe', self.get_summe(data)),
        ('results', data)
    ]))

и don не забыли удалить дополнительный код, который вы добавили, поскольку он нам не нужен ни двумя способами

...