简体   繁体   中英

Django Rest Framework Calculations in Serializer?

I'm working with a finance application, and due to the way that floating point math works, have decided to store all values in the database as cents (so dollar amount * 100). I have been banging my head against a wall to get the serializer to perform two calculations for me. On create/update accept a float value but then before saving to the database do value*100. Then on get, do value/100.

I got it half working using a SerializerMethodField , but that seemed to remove my ability to do create/update actions. I also at one point had something that kind of worked for create/update by changing the serializer.save() method in the view and adding an IntegerField validator on the field, but then that broke the SerializerMethodField .

In short, I'm stuck. lol

Here is my very simple model:

class Items(models.Model):
    user = models.ForeignKey(
        'CustomUser',
        on_delete=models.CASCADE,
    )
    name = models.CharField(max_length=60)
    total = models.IntegerField()

My views for this item:

class GetItems(generics.ListCreateAPIView):
    serializer_class = ItemsSerializer
    permission_classes = [permissions.IsAuthenticated, IsAuthorOrDenied]
    user = serializers.HiddenField(default=serializers.CurrentUserDefault(), )

    def get_queryset(self):
        user = self.request.user
        return Items.objects.filter(user=user)

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


class SingleItem(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = ItemsSerializer
    permission_classes = [permissions.IsAuthenticated, IsAuthorOrDenied]
    user = serializers.HiddenField(default=serializers.CurrentUserDefault(), )

    def get_queryset(self):
        user = self.request.user
        return Items.objects.filter(user=user)

    def perform_update(self, serializer):
        serializer.save(user=self.request.user)

And my serializer

class ItemsSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'name', 'budget_total')
        model = models.Items

I feel like I should be doing more in my Serializer and less in my views, but that may be a completely different question all together.

Thanks in advance for the help!

Custom Serializer Field

You could write a custom field to handle the data:

class BudgetField(serializers.Field):

    def to_representation(self, value):
        # You can decide here how you want to return your data back
        return value / 100

    def to_internal_value(self, data):
        # this will be passed to validated_data, so will be used to create/update instances
        # you could do some validation here to make sure it is a float
        # https://www.django-rest-framework.org/api-guide/fields/#raising-validation-errors
        return int(data * 100)

Then use the custom field on your serializer.

class ItemsSerializer(serializers.ModelSerializer):

    total = BudgetField()

    class Meta:
        fields = ('id', 'name', 'total')
        model = models.Items

Override .update() and .create()

You could also choose to override these methods on the serializer.

class ItemsSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'name', 'budget_total')
        model = models.Items

    def create(self, validated_data):
        # Modify validated_data with the value you need
        return super().create(validated_data)

    def update(self, instance, validated_data):
        # Modify validated_data with the value you need
        return super().update(instance, validated_data)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM