ListCreateAPIView POST with an annotated field that's in serializer not model

554 views django
5

I'm building a simple budgeting app to work on learning Django & React. I've used DRF to build an API to create and get transactions from the database. I'm currently calculating the total running balance on the fly when I do my GET. This has been working well, but when I do a POST I get an error that my dynamic balance field is required since that field is in my serializer. How can I get around this?

views.py

class CreateView(generics.ListCreateAPIView):
    """This class defines the GET & POST behavior of the rest api."""

    queryset = Transaction.objects.all()

    # This is the balance that's calculated on the fly
    queryset_with_balance = queryset.annotate(balance=Window(Sum('amount'),
                                                             order_by=F('created_time').asc())).all().order_by('-created_time')

    serializer_class = TransactionSerializer

    def perform_create(self, serializer):
        """Save the post data when creating a new transaction."""
        serializer.save()

    def get_queryset(self):
        return self.queryset_with_balance

serializers.py

class TransactionSerializer(serializers.ModelSerializer):
    balance = serializers.DecimalField(decimal_places=2, max_digits=19)

    class Meta:
        """Meta class to map serializer's fields with the model fields."""
        model = Transaction
        fields = ('id', 'date', 'payee', 'category',
                  'amount', 'balance', 'created_time', 'modified_time')

models.py

class Transaction(models.Model):
    date = models.DateField()
    payee = models.CharField(max_length=256)
    category = models.CharField(max_length=256)
    amount = MoneyField(max_digits=19,
                        decimal_places=2,
                        default_currency='USD')    
    created_time = models.DateTimeField(auto_now_add=True)
    modified_time = models.DateTimeField(auto_now=True)

answered question

Do you need this balance field while HTTP POST ?

you can move queryset_with_balance or only annotate to def get_queryset(self):

Balance is only needed on the GET. I'm not storing that in the DB.

@brewcrazy Check my answer below :) Hope that will solve the issue :)

1 Answer

1

set balance field as read_only as below,

class TransactionSerializer(serializers.ModelSerializer):
    balance = serializers.DecimalField(decimal_places=2, max_digits=19, read_only=True)
    # your code



From the DRF doc

Read-only fields are included in the API output, but should not be included in the input during create or update operations.

posted this

Have an answer?

JD

Please login first before posting an answer.