Alex Rothberg
Alex Rothberg

Reputation: 10993

Django REST Framework FileField Data in JSON

In Django REST Framework (DRF), how do I support de-Serializing base64 encoded binary data?

I have a model:

class MyModel(Model):
   data = models.FileField(...)

and I want to be able to send this data as base64 encoded rather than having to multi-part form data or a "File Upload". Looking at the Parsers, only FileUploadParser and MultiPartParser seem to parse out the files.

I would like to be able to send this data in something like JSON (ie send the binary data in the data rather than the files:

{
 'data':'...'
}

Upvotes: 2

Views: 4410

Answers (3)

Francisco Puga
Francisco Puga

Reputation: 25149

This is an old question, but for those looking for an up-to-date solution, there is a plugin for DRF (drf_base64) that handles this situation. It allows reading files encoded as base64 strings in the JSON request.

So given a model like:

class MyModel(Model):
   data = models.FileField(...)

and an expected json like:

{
  "data": "data:image/png;base64,iVBORw0KGgoA ....",
  ...
}

The (des) serialization can be handled just importing from drf_base modules instead of the drf itself.

from drf_base64.serializers import ModelSerializer
from .models import MyModel

class MyModel(ModelSerializer):

    class Meta:
        model = MyModel

Just remember that is posible to get a base64 encoded file in javascript with the FileReader API.

Upvotes: 2

Alex Rothberg
Alex Rothberg

Reputation: 10993

I solved it by creating a new Parser:

def get_B64_JSON_Parser(fields):
    class Impl(parsers.JSONParser):
        media_type = 'application/json+b64'

        def parse(self, *args, **kwargs):
            ret = super(Impl, self).parse(*args, **kwargs)
            for field in fields:
                ret[field] = SimpleUploadedFile(name=field, content=ret[field].decode('base64'))
            return ret
    return Impl

which I then use in the View:

class TestModelViewSet(viewsets.ModelViewSet):
    parser_classes = [get_B64_JSON_Parser(('data_file',)),]

Upvotes: 4

Carlton Gibson
Carlton Gibson

Reputation: 7386

There's probably something clever you can do at the serialiser level but the first thing that comes to mind is to do it in the view.

Step 1: Write the file. Something like:

fh = open("/path/to/media/folder/fileToSave.ext", "wb")
fh.write(fileData.decode('base64'))
fh.close()

Step 2: Set the file on the model. Something like:

instance = self.get_object()
instance.file_field.name = 'folder/fileToSave.ext' # `file_field` was `data` in your example
instance.save()

Note the absolute path at Step 1 and the path relative to the media folder at Step 2.

This should at least get you going.

Ideally you'd specify this as a serialiser field and get validation and auto-assignment to the model instance for free. But that seems complicated at first glance.

Upvotes: 0

Related Questions