MultiPartParserError :- Invalid boundary
Question: Im trying to send some data and file using Python requests module to my django
rest application but get the below error.

    
    
        raise MultiPartParserError('Invalid boundary in multipart: %s' % boundary)
    MultiPartParserError: Invalid boundary in multipart: None
    

Code:-

    
    
    import requests
    payload={'admins':[
                        {'first_name':'john'
                        ,'last_name':'white'
                        ,'job_title':'CEO'
                        ,'email':'test1@gmail.com'
                        },
                        {'first_name':'lisa'
                        ,'last_name':'markel'
                        ,'job_title':'CEO'
                        ,'email':'test2@gmail.com'
                        }
                        ],
            'company-detail':{'description':'We are a renowned engineering company'
                        ,'size':'1-10'
                        ,'industry':'Engineering'
                        ,'url':'http://try.com'
                        ,'logo':''
                        ,'addr1':'1280 wick ter'
                        ,'addr2':'1600'
                        ,'city':'rkville'
                        ,'state':'md'
                        ,'zip_cd':'12000'
                        ,'phone_number_1':'408-393-254'
                        ,'phone_number_2':'408-393-221'
                        ,'company_name':'GOOGLE'}
            }
    files = {'upload_file':open('./test.py','rb')}
    import json
    headers = {'content-type' : 'application/json'}      
    headers = {'content-type' : 'multipart/form-data'}      
    
    #r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=json.dumps(payload),headers=headers,files=files)
    r = requests.post('http://127.0.0.1:8080/api/create-company-profile/',data=payload,headers=headers,files=files)
    print r.status_code
    print r.text
    

Django code:-

    
    
    class CompanyCreateApiView(CreateAPIView):
        parser_classes = (MultiPartParser, FormParser,)
        def post(self, request, *args, **kwargs):
            print 'request ==', request.data
    


Answer: Okay, I forgot about your headers. According to [the
spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html):

>
>     Content-Type   = "Content-Type" ":" media-type
>  
>
> MIME provides for a number of "multipart" types -- encapsulations of one or
> more entities within a single message-body. All multipart types share a
> common syntax, ... and MUST include a boundary parameter as part of the
> media type value.

Here is what a request containing multipart/form-data looks like:

    
    
    POST /myapp/company/ HTTP/1.1
    Host: localhost:8000
    Content-Length: 265
    Accept-Encoding: gzip, deflate
    Accept: */*
    User-Agent: python-requests/2.9.0
    Connection: keep-alive
    Content-Type: multipart/form-data; boundary=63c5979328c44e2c869349443a94200e   
    
    --63c5979328c44e2c869349443a94200e
    Content-Disposition: form-data; name="hello"
    
    world
    --63c5979328c44e2c869349443a94200e
    Content-Disposition: form-data; name="mydata"; filename="data.txt"
    
    line 1
    line 2
    line 3
    line 4
    
    --63c5979328c44e2c869349443a94200e--
    

See how the sections of data are separated by the boundary:

    
    
    --63c5979328c44e2c869349443a94200e--
    

The idea is to use something for a boundary that is unlikely to appear in the
data. Note that the boundary was included in the `Content-Type` header of the
request.

That request was produced by this code:

    
    
    import requests
    
    myfile = {'mydata': open('data.txt','rb')}
    
    r = requests.post(url, 
            #headers = myheaders
            data = {'hello': 'world'}, 
            files = myfile
    ) 
    

It looks like you were paying careful attention to the following note in the
django-rest-framework [docs](http://www.django-rest-framework.org/api-
guide/parsers/#multipartparser):

> Note: When developing client applications always remember to make sure
> you're setting the Content-Type header when sending data in an HTTP request.
>
> If you don't set the content type, most clients will default to using
> 'application/x-www-form-urlencoded', which may not be what you wanted.

But when you are using `requests`, if you specify the `Content-Type` header
yourself, then `requests` assumes that you know what you're doing, and it
doesn't overwrite your `Content-Type` header with the `Content-Type` header it
would have provided.

You didn't provide the boundary in your `Content-Type` header--as required.
How could you? You didn't assemble the body of the request and create a
boundary to separate the various pieces of data, so you couldn't possibly know
what the boundary is.

When the `django-rest-framework` note says that you should include a `Content-
Type` header in your request, what that really means is:

> You or any programs you use to create the request need to include a
> `Content-Type` header.

So @AChampion was exactly right in the comments: let `requests` provide the
`Content-Type header`, after all the `requests` docs advertise:

> Requests takes all of the work out of Python HTTP/1.1

`requests` works like this: if you provide a `files` keyword arg, then
requests uses a `Content-Type` header of `multipart/form-data` and also
specifies a boundary in the header; then `requests` assembles the body of the
request using the boundary. If you provide a `data` keyword argument then
requests uses a `Content-Type` of `application/x-www-form-urlencoded`, which
just assembles all the keys and values in the dictionary into this format:

    
    
    x=10&y=20
    

No boundary required.

And, if you provide both a `files` keyword arg and a `data` keyword arg, then
requests uses a `Content-Type` of `multipart/form-data`.

