DRFのDecimalFieldから末尾のゼロを除外

Django REST framework (DRF) において、DecimalFieldから末尾のゼロを除去する方法です。具体的には以下のように挙動を変更します。

# 現在
Decimal('0.001000000') >> "0.001000000"
# 期待する結果
Decimal('0.001000000') >> "0.001"

この機能は以下のPRで追加されましたが、まだリリースされていません。

github.com

https://github.com/Krolken/django-rest-framework/blob/92bcdd021a51d047836c6fdfdc4b981930717131/docs/api-guide/fields.md#decimalfield

・ normalize_output
Will normalize the decimal value when serialized. This will strip all trailing zeroes and change the value's precision to the minimum required precision to be able to represent the value without loosing data. Defaults to False.

また、この機能は DecimalField(normalize_output=True) で有効になるため、全体への適用には少々手間がかかります。
そこで、settingsの拡張を提案しましたが、現在DRFはメンテナンスフェーズ*1にあるため、提案は採用されませんでした。

github.com

そこで、#6514の変更を参考に、 quantized.normalize() を追加したカスタムフィールドを作成しました。
このカスタムフィールドを ModelSerializer.serializer_field_mappingmodels.DecimalFieldマッピングすることで、カスタムフィールドを標準適用します。
(COERCE_DECIMAL_TO_STRING関連の処理は使わないので削っています。)

import decimal

from django.db import models
from django.utils.formats import localize_input
from rest_framework import serializers


class NormalizedDecimalField(serializers.DecimalField):
    def to_representation(self, value):
        if value is None:
            return ''

        if not isinstance(value, decimal.Decimal):
            value = decimal.Decimal(str(value).strip())

        quantized = self.quantize(value)

        quantized = quantized.normalize()

        if self.localize:
            return localize_input(quantized)

        return '{:f}'.format(quantized)


class CustomModelSerializer(serializers.ModelSerializer):
    serializer_field_mapping = (
        serializers.ModelSerializer.serializer_field_mapping.copy()
    )
    serializer_field_mapping[models.DecimalField] = NormalizedDecimalField

あとはシリアライザの基底クラスを CustomModelSerializer に変更するだけで、各DecimalFieldから末尾のゼロを除外できます。

- class MySerializer(serializers.ModelSerializer):
+ class MySerializer(CustomModelSerializer):

モデルのプロパティがDecimal値を返す場合には、シリアライザクラスに NormalizedDecimalField を明示的に定義してください。

class MySerializer(CustomModelSerializer):
    my_property = NormalizedDecimalField(max_digits=..., decimal_places=...)