iuuujkl
iuuujkl

Reputation: 2384

access attribute via serializer django

I got following models:

class OrderItem(models.Model):
    ordered_amount = models.IntegerField(validators=[MinValueValidator(0)])
    amount = models.IntegerField(default=0)

    order = models.ForeignKey(
        Order, on_delete=models.CASCADE, related_name="order_items"
    )

class Order(models.Model):
    reference = models.CharField(max_length=50)
    purchase_order = models.CharField(max_length=15, blank=True, null=True)

I'm now writing a serializer for listing orders. In this OrderSerializer I need to access amount and ordered_amount in the OrderItem class. How do I do this? This is What I have now:

class AdminOrderListSerializer(serializers.ModelSerializer):
    amount = serializers.IntegerField()
    ordered_amount = serializers.IntegerField()

    class Meta:
        model = Order
        fields = [
            "purchase_order",
            "reference",
            "amount",
            "ordered_amount",
        ]

    # noinspection PyMethodMayBeStatic
    def validate_amount(self, order):
        if order.order_items.amount:
            return order.order_items.amount
        return

    # noinspection PyMethodMayBeStatic
    def validate_ordered_amount(self, order):
        if order.order_items.ordered_amount:
            return order.order_items.ordered_amount
        return

This gives me following error:

AttributeError: Got AttributeError when attempting to get a value for field amount on serializer AdminOrderItemListSerializer. The serializer field might be named incorrectly and not match any attribute or key on the Order instance. Original exception text was: 'Order' object has no attribute 'amount'.

Upvotes: 0

Views: 33

Answers (1)

ruddra
ruddra

Reputation: 51988

There are many ways to that, one of them is SerializerMethodField:

from django.db.models import Sum

class AdminOrderListSerializer(serializers.ModelSerializer):
    amount = serializers.SerializerMethodField()
    ordered_amount = serializers.SerializerMethodField()

    def get_amount(self,obj):
        return obj.order_items.aggregate(sum=Sum('amount'))['sum']


    def get_ordered_amount(self,obj):
        return obj.order_items.aggregate(sum=Sum('order_amount'))['sum']

Optimized solution

Another way of achieving this is to annotate the data to queryset, and access them in serializer. For that, you need to change in view:

class SomeView(ListAPIView):
    queryset = Order.objects.annotate(amount=Sum('order_items__amount'),order_amount=Sum('order_items__order_amount'))

This is a optimized solution because it reduces database hits(it only hits once).

Upvotes: 1

Related Questions