Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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')
like image 856
pyprism Avatar asked Dec 24 '22 04:12

pyprism


1 Answers

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')
like image 152
Rahul Gupta Avatar answered Feb 01 '23 23:02

Rahul Gupta