5

I need to post an array of integers to a DRF serializer.

The serializer is:

class ItemSerializer(serializers.Serializer):
    id = serializers.IntegerField(required = False)
    selected_items = serializers.ListField(child = serializers.IntegerField())

From the FE I simply post via typescript an array:

createItem () {
    let tmp: any = {};
    const itemData = new FormData();
    itemData.append('id',1);
    itemData.append('selected_items', this.current.selected_items.map( e => e.id))

    return this.itemService.createItem( itemData )
        .subscribe( data => this.goBack( data ),
            err => {
                console.log( err );
                this.toastr.error( 'Item not saved', 'Error' )
            } );
}

itemService.createItem only does a http.post

When FE sends data to BE the selected_items field is encoded as selected_items=1,2 (verified via wireshark). When data is parsed from DRF the field is encoded as selected_items=['1,2']. So the field is not validated because 1,2 is not a valid integer.

Christian
  • 51
  • 1
  • 6

1 Answers1

3

If you are getting comma separated values in request, then you might want to convert it to an actual list before it goes for the validation.

just override the to_internal_value() method in your serializer to convert values.

class ItemSerializer(serializers.Serializer):
    id = serializers.IntegerField(required = False)
    selected_items = serializers.ListField(child = serializers.IntegerField())

    def to_internal_value(self, data):
        """
        method is called to restore a primitive datatype into its internal python representation. This method should raise a serializers.ValidationError if the data is invalid. 
        reference: https://www.django-rest-framework.org/api-guide/fields/#custom-fields
        """
        # Convert comma separated digits to list of integers
        data['selected_items'] = data['selected_items'].split(',') if data['selected_items'] else []
        return data

or else, you can write a custom field-level validation:

class ItemSerializer(serializers.Serializer):
    id = serializers.IntegerField(required = False)
    selected_items = serializers.ListField(child = serializers.IntegerField())

    def validate_selected_items(self, value):
        """
        You can specify custom field-level validation by adding .validate_<field_name> methods to your Serializer subclass.
        reference: https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation
        """
        # Convert comma separated digits to list of integers
        return value.split(',') if value else []
  • 1
    Thx. I expected the DRF manages the deserialization of the field automatically as it does for all other fields. – Christian Jun 21 '20 at 13:55
  • 1
    I used another solution: I declared the field as a JSONField and pop it from validated_data in create and update methods. Also in this case, as the secondo solution proposed by @Vedprakash it reuiqres very few line of code. – Christian Jun 27 '20 at 11:39