Escher
Escher

Reputation: 5776

How to override representation of a FilelField as its contents in Django Rest Framework?

Let's say I'm trying to serialize a Configuration model that looks like this:

class Configuration(models.Model):
    name = models.CharField()
    data = models.FileField()

The data is data that the front-end application needs to know for presentation purposes, but is of no use to the back-end. I want its serialized representation to accept and return data's content as a string, but for data's content to be actually stored in a file as it's of no relevance to the back-end application. Here's what I've got:

class DataField(serializers.FileField):
    def to_internal_value(self, data):
        try:
            return data.read()
        except Exception as e: # not really sure what could turn up here
            raise ValidationError(e)

class ForecastConfigSerializer(serializers.ModelSerializer):
    data = DataField()
    class Meta:
        model = Configuration
        fields = ('data', 'name',)

This gives me a problem when django.db.models.fields.files wants to save:

'bytes' object has no attribute '_committed'.

Fair enough, I'm probably screwing up things with to_internal_value as I read the data. I take it it works for serializing an instance, but not creating an instance from serialized data.

How do I do this then?

Upvotes: 0

Views: 886

Answers (1)

user8060120
user8060120

Reputation:

models.py:

class Configuration(models.Model):
    name = models.CharField()
    data = models.FileField()

    @property
    def data_src(self):
        return self.data.read() if self.data else ''

serializers.py

You need generate new file name by your logic or use OverwriteStorage snippet

from django.core.files.base import ContentFile

class ForecastConfigSerializer(serializers.ModelSerializer):
    data = serializers.CharField(source='data_src', read_only=True)
    class Meta:
        model = Configuration
        fields = ('data', 'name',)

    def create(self, validated_data):
        data_src = validated_data.pop('data_src')
        instance = super(ForecastConfigSerializer, self).create(validated_data)
        request = self.context.get('request')
        f = ContentFile(data_src if data_src else '')
        # generate new file name by your logic
        new_file_name = 'CHANGE_IT.json'
        instance.data.save(new_file_name, f)
        return instance

hope it help

Upvotes: 1

Related Questions