Skip to content
Advertisement

DRF Serializer – Accept field but don’t use it in `create` or `update`

I have a model Message that has a FileField. My API accepts files in Base64 encoding so they can be sent alongside other data.

To know a filename and an extension, there is one more field attachment_filename in the serializer that is not a model field. It is used inside Base64Field.

I want to be able to validate if there are both attachment_filename , attachment, or none of them.

The problem is that if the attachment_filename is read-only, it is not present in validatedata variable.

On the other hand, if it’s required=False, allow_null=True, the serializer raises an error when creating a message:

TypeError: ChatMessage() got an unexpected keyword argument 'attachment_filename'

Code:

class Base64File(Base64FileField):  # todo make accept a list of extensions (finite eg. pdf, xlsx, csv, txt )
    ALLOWED_TYPES = ['pdf', 'xlsx', 'png', 'jpg', 'jpeg', 'docx', 'doc', 'zip']

    def get_file_extension(self, filename, decoded_file):
        extension = self.get_full_name().split('.')[-1]
        return extension

    def get_file_name(self, decoded_file):
        attachment_filename = self.get_full_name()
        return '.'.join(attachment_filename.split('.')[:-1])

    def get_full_name(self):
        return self.context['request'].data['attachment_filename']  # todo validate name

class ChatMessageSerializer(serializers.ModelSerializer):
    attachment = Base64File(required=False)
    attachment_filename = serializers.CharField(required=False, allow_null=True)

    class Meta:
        model = ChatMessage
        fields = '__all__'


    def validate(self, data):
        """
        Validation of start and end date.
        """
        attachment = data.get('attachment')
        attachment_filename = data.get('attachment_filename')
        if bool(attachment) ^ bool(attachment_filename):
            raise serializers.ValidationError("Either none or both 'attachment' and 'attachment_filename' must be present")
        # del data['attachment_filename'] # works but dirty
        return data

How to make it work?

EDIT

I managed to make it work by adding

del data['attachment_filename']

before validate method return but that seems to be too “dirty”.

Advertisement

Answer

You should handle this behavior in serializer.save method, for example, you can pop it from validated_data like that:

    def save(self, **kwargs):
        self.validated_data.pop("attachment_filename")

        return super().save(**kwargs)
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement