4

I am trying to upload file with some form data. For testing my api I am using Postman.When I try to POST with file and other fields, I got this error

{
  "detail": "JSON parse error - 'utf-8' codec can't decode byte 0xbf in position 10: invalid start byte"
}

Here is my model:

class Music(models.Model):
    album = models.ForeignKey(Album, related_name='tracks')
    playlist = models.ForeignKey(Playlist, null=True, related_name='tracks')
    name = models.CharField(max_length=200, unique=True)
    dropbox_id = models.CharField(max_length=500, null=True)
    favorite = models.BooleanField(default=False)
    created_at = models.DateField(auto_now_add=True)
    counter = models.IntegerField(default=0)

serializer:

class MusicSerializer(serializers.ModelSerializer):
    file = serializers.FileField(required=True)

    class Meta:
        model = Music
        fields = ('id', 'favorite', 'created_at', 'counter', 'file', 'name', 'album', 'playlist')

and view :

class MusicViewSet(viewsets.ModelViewSet):
    queryset = Music.objects.all()
    serializer_class = MusicSerializer

    def perform_create(self, serializer):
        file_obj = self.request.FILES['file']
        dbx = dropbox.Dropbox(JSON_DATA['dropbox_access_token'])
        res = dbx.files_upload(file_obj, '/', autorename=True, mute=True)
        print(res)
        serializer.save(dropbox_id='x')
pyprism
  • 2,928
  • 10
  • 46
  • 85
  • Have you set "content-type: application/json" in HEADER? – Mohammad Mustaqeem Jun 23 '16 at 09:17
  • Yes of course. There are three headers : Authorization, Accept and Content-Type – pyprism Jun 23 '16 at 09:23
  • Content-type is not needed. Remove it and then check. – Mohammad Mustaqeem Jun 23 '16 at 09:28
  • Can you show the request? I suspect that you can not upload the file the way you are trying to... Also as a starting point look at this: https://gist.github.com/yprez/7704036 – Ivan Genchev Jun 23 '16 at 09:53
  • 2
    Json cannot be used to send direct files, you should send data with `multipart/form-data` content type instead. Also, you would need to specify a `MultiPartParser` in `parser_classes` in your `ViewSet` then if its not specified in the settings. – Rahul Gupta Jun 23 '16 at 16:32

1 Answers1

10

You cannot upload files with JSON request content.

You should instead send data with multipart/form-data content. DRF's MultiPartParser handles multipart HTML form content which supports file uploads.

MultiPartParser
Parses multipart HTML form content, which supports file uploads. Both request.data will be populated with a QueryDict.

You will typically want to use both FormParser and MultiPartParser together in order to fully support HTML form data.

In your MusicViewSet, you can define FormParser and MultiPartParser, if they are not defined in your settings so that DRF can parse the multipart HTML form content. You can access the file using serializer.validated_data in perform_create() method.

class MusicViewSet(viewsets.ModelViewSet):
    queryset = Music.objects.all()
    serializer_class = MusicSerializer
    parser_classes = (FormParser, MultiPartParser) # set parsers if not set in settings. Edited

    def perform_create(self, serializer):
        file_obj = serializer.validated_data['file'] # access file
        dbx = dropbox.Dropbox(JSON_DATA['dropbox_access_token'])
        res = dbx.files_upload(file_obj, '/', autorename=True, mute=True)
        serializer.save(dropbox_id='x')
Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126