Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework Refusing To Accept MultiPart Form Data

I am trying to post data which has nested json, an image and other data. The json looks like this:

{
    "id": ,
    "venue": {
        "id": ,
        "name": "",
        "city": "",
        "address": "",
        "rating": null,
        "point": null
    },
    "name": "",
    "time": "",
    "event_pic": null,
    "description": "",
    "event_type": "Movie",
    "invite_only": ,
    "free": ,
    "age_restriction": ,
    "ticket_price": ,
    "user": 
}

I am running into a problem where for some reason if I try to use multipart form to upload I get an error message like this:

Request http://zacmwa.pythonanywhere.com/api/events/ (7417ms)
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Server: openresty/1.9.15.1
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Date: Tue, 14 Feb 2017 13:21:26 GMT
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Content-Type: application/json
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Transfer-Encoding: chunked
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Connection: keep-alive
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Vary: Accept
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: X-Frame-Options: SAMEORIGIN
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: Allow: GET, POST, OPTIONS
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: {"venue":["This field is required."]}
    02-14 16:21:26.468 7133-7762/com.wyat.wyat D/OkHttp: <-- END HTTP (37-byte body)

It says {"venue":["This field is required."]} and sends me a 400 Bad Request.

When I sent from Postman I could not send in multipart form but when I used application/json header I was able to solve this.However when using application/json I am unable to send images.

Why isn't it seeing the json object being sent?How does DRF want nested objects to be sent?

In the browsable api form I can create a nested json object and image easily without changing anything. How do I do this for other clients?

like image 208
zacmwa Avatar asked Feb 15 '17 15:02

zacmwa


2 Answers

TL;DR: You can't do that yet.

Longer version:

You can't send images along with JSON out of the box. Multipart doesn't support JSON (cf https://github.com/tomchristie/django-rest-framework/issues/4881).

The alternative would be to use forms along with the image but forms don't support nested data at the moment.

There might be some workaround with base 64 encoded images sent within the JSON but I haven't play with those so I can't say if it's a good option or not.

PS: your issue is because it's sending the data as form encoded. As it doesn't support nested data, it'll complain you field isn't working.

like image 63
Linovia Avatar answered Sep 30 '22 18:09

Linovia


Make sure you have added MultiPartParser in your DRF Parser configuration in your settings file.

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.MultiPartParser'
        #...
    )
}

Also verify that you have specified enctype='multipart/form-data' in your html form tag

Edit:- You can't send nested data as multipart content type, and you can't send raw byte data in json. Either use unnested data or encode file data using base64 or similar.

import base64
with open ('sample.txt') as file:
    encoded_content = base64.b64encode(file.read())

Don't forget to decode file content in your view.

like image 43
hspandher Avatar answered Sep 30 '22 19:09

hspandher