coddingtonbear / django-measurement

Easily store, retrieve, and convert measurements of weight, volume, distance, area and more.
MIT License
145 stars 33 forks source link

django-Measurement does not have a django rest framework serializer field #107

Open limonrojo-nm opened 3 years ago

limonrojo-nm commented 3 years ago

Hi. I've wrote a serializer field to use django-measurement with django rest framework beacuse i could'n find it nowhere. Something near this was discussed here. (I'm not sure this is the best way to share this... let me know).

MeasurementSerializerField.py:

import decimal
from rest_framework import serializers

def is_valid_unit(unit_to_validate, measurement_class):
    return unit_to_validate in measurement_class.get_units()

def is_valid_decimal(value_to_validate):
    return decimal.Decimal(value_to_validate)

class MeasurementSerializerField(serializers.Field):
    '''
    Basic generic serializer field for Django REST Framework integration for django-measurement model fields.
    https://github.com/coddingtonbear/django-measurement
    '''

    def __init__(self, measurement_class, *args, **kwargs):
        super(MeasurementSerializerField, self).__init__(*args, **kwargs)
        self.measurement_class = measurement_class

    def to_representation(self, obj):
        return {
            'unit': obj.unit,
            'value': obj.value
        }

    default_error_messages = {
        'invalid_unit': 'Invalid unit. {invalid_unit} is not a valid {measurement_class.__name__} unit',
        'invalid_value': 'Invalid value. {invalid_value} is not a valid {measurement_class.__name__} value',
    }
    def to_internal_value(self, data):
        if not is_valid_unit(data['unit'], self.measurement_class):
            self.fail(
                'invalid_unit',
                invalid_unit=data['unit'],
                measurement_class=self.measurement_class
            )

        if not is_valid_decimal(data['value']):
            self.fail(
                'invalid_value',
                invalid_value=data['value'],
                measurement_class=self.measurement_class
            )

        return self.measurement_class(**{data['unit']: data['value']})

And the implementation could be like in ModelWithMeasurementsSerializer.py

# all imports and so

class ModelWithMeasurementsSerializer(serializers.ModelSerializer):
    width = MeasurementSerializerField(measurement_class=Distance, required=False)
    height = MeasurementSerializerField(measurement_class=Distance, required=False)
    length = MeasurementSerializerField(measurement_class=Distance, required=False)
    weight = MeasurementSerializerField(measurement_class=Weight, required=False)

    class Meta:
        model = ModelWithMeasurements
        fields = '__all__'

Perhaps something like that could be included in the library.

codingjoe commented 3 years ago

Hi @nmimagenysonido,

I'd love to see a DRF field for this package. You are welcome to propose one in a PR.

Best, Joe

limonrojo-nm commented 2 years ago

Hi @nmimagenysonido,

I'd love to see a DRF field for this package. You are welcome to propose one in a PR.

Best, Joe

Joe, ALAP (as late...) the PR was done. Here the PR