7

For example I tried that command via terminal:

curl -F "profileImage=@/home/user/image.jpg" -F "{'firstName':'hello'};type=application/json" http://127.0.0.1:8000/api/v1/signup/

Then I received the request object like that:

print request.FILES
# <MultiValueDict: {u'profileImage': [<InMemoryUploadedFile: image.jpg (image/jpeg)>]}>
print request.DATA
# <QueryDict: {u"{'firstName':'hello'};content-type": [u'application/json']}>

The image is ok, but QueryDict is not represented correctly - all JSON file is a key and content-type is a value.

In Django use these parsers:

parser_classes = (MultiPartParser, FormParser, JSONParser,)

I necessary need to send text data via JSON structure .

JJD
  • 50,076
  • 60
  • 203
  • 339
alexche8
  • 1,270
  • 3
  • 19
  • 26

5 Answers5

2

If you want to POST with multipart/form-data content-type, you can't also specify application/json. The simple fix for this is to send the form data in url-encoded format. Try this command:

curl -F "profileImage=@/home/user/image.jpg" -F "firstName=hello" http://127.0.0.1:8000/api/v1/signup/
xjtian
  • 966
  • 1
  • 7
  • 15
  • Are you sure that I can't use it? I found similar example answer that generate request body with application/json. http://stackoverflow.com/questions/9081079/rest-http-post-multipart-with-json/9082243#9082243 – alexche8 May 27 '14 at 19:02
  • 1
    @alexche8 The above approach will work with a DRF application. Why do you need JSON? Also, see http://stackoverflow.com/questions/3938569/how-do-i-upload-a-file-with-metadata-using-a-rest-web-service for a more relevant discussion. – xjtian May 27 '14 at 19:23
2

I came up with a solution like this:

class MultiPartJSONParser(parsers.MultiPartParser):

    def parse(self, stream, media_type=None, parser_context=None):

        dataAndFiles = super(MultiPartJSONParser, self).parse(stream, media_type, parser_context)

        try:
            jsonData = json.loads(dataAndFiles.data.get('data'))
        except ValueError as exc:
            raise parsers.ParseError('JSON parse error - %s' % six.text_type(exc))

        # make data mutable, insert json data, and remove raw data
        dataAndFiles.data = data = dataAndFiles.data.copy()
        data.update(jsonData)
        del data['data']

        return dataAndFiles

It assumes that the JSON part is sent as a form field called 'data'.

If you want to get really slick, you could probably parse the data field according to the media type value of the Accept header. Alternatively, you could POST the data as a file and parse according to its content type.

Note that to use this parser class, you'll need to set the following default settings:

REST_FRAMEWORK = {
    'FORM_METHOD_OVERRIDE': None,
    'FORM_CONTENT_OVERRIDE': None,
}

That is due to this bug: https://github.com/tomchristie/django-rest-framework/issues/1346

jacob
  • 2,762
  • 1
  • 20
  • 49
1

the parameter to specify the content-type is just "type="

curl -F "profileImage=@/home/user/image.jpg" -F "{'firstName':'hello'};type=application/json" http://127.0.0.1:8000/api/v1/signup/

However, I don't think that will allow the JSONParser to take the information..., but you can try :)

fixmycode
  • 8,220
  • 2
  • 28
  • 43
1

Here :-

curl -vvv -X POST -H "Content-Type:multipart/form-data" -H "Accept:application/json" -H -F "username=sample" -F "password=something" -F "image=@Mercury.gif" http://127.0.0.1:8000/api/objects

No need to type accepts application/json. Django will automatically treat these as dictionary objects.

Print request.DATA and request.FILES will give you

<QueryDict: {u'username': [u'sample'] , u'password': [u'something']}>
<MultiValueDict: {u'image': [<InMemoryUploadedFile: Mercury.gif (image/gif)>]}>
Dharmanshu Kamra
  • 601
  • 3
  • 8
  • 18
  • Thanks, It resolve a half of issue. Querydict and Image arrived fine but I have yet need send text data via json structure '{key: val, key : val}. – alexche8 May 29 '14 at 17:03
0

Thanks xjtian - link that you pasted in comment + some researches make solution. So:

  1. If you want sending json data + file - send two requests. First will create object on backend and give id to app. Second will update object with file using gived id. More info there.

  2. If you don't care about data types - send request via "multipart/form-data".

Thanks to all for answers, you realy helps, but I think this one is more appropriate for REST architecture.

Community
  • 1
  • 1
alexche8
  • 1,270
  • 3
  • 19
  • 26