pyprism
pyprism

Reputation: 3008

Django REST Framework file upload

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')

Upvotes: 4

Views: 19528

Answers (1)

Rahul Gupta
Rahul Gupta

Reputation: 47846

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')

Upvotes: 10

Related Questions