title: Parsing multipart/form-data in django-rest-framework
body: <p>I'm having some difficulties parsing multipart form data when using the django-rest-framework.  I've set up a minimal view to just echo back the request data:</p>
  
  <pre class="lang-py prettyprint-override"><code>from rest_framework.views import APIView
  from rest_framework.response import Response
  from rest_framework.parsers import MultiPartParser, FormParser
  
  
  class FileUpload(APIView):
      parser_classes = (MultiPartParser, FormParser, )
  
      def post(self, request, format=None, *args, **kwargs):
          return Response({'raw': request.data, 'data': request._request.POST,
                           'files': str(request._request.FILES)})
  </code></pre>
  
  <p>I am expecting that <code>raw</code> (slightly badly named I admit) contains effectively the same data as <code>request._request.POST</code> and <code>request._request.FILES</code>.  </p>
  
  <p>If I <code>POST</code> to the view with <code>Content-Type= application/x-www-form-urlencoded</code> this works as expected:</p>
  
  <pre><code>$ http -v --form POST http://localhost:8000/upload/api/ course=3 name=name
  
  POST /upload/api/ HTTP/1.1
  Accept: */*
  Accept-Encoding: gzip, deflate
  Connection: keep-alive
  Content-Length: 18
  Content-Type: application/x-www-form-urlencoded; charset=utf-8
  Host: localhost:8000
  User-Agent: HTTPie/0.9.2
  
  course=3&amp;name=name
  
  HTTP/1.0 200 OK
  Allow: POST, OPTIONS
  Content-Type: application/json
  Date: Thu, 17 Dec 2015 16:52:37 GMT
  Server: WSGIServer/0.2 CPython/3.4.3
  Vary: Accept, Cookie
  X-Frame-Options: SAMEORIGIN
  
  {
      "data": {
          "course": "3",
          "name": "name"
      },
      "files": "&lt;MultiValueDict: {}&gt;",
      "raw": {
          "course": "3",
          "name": "name"
      }
  }
  </code></pre>
  
  <p>However if I post with <code>Content-Type=multipart/form-data</code> I get the following:</p>
  
  <pre><code>$ http -v --form POST http://localhost:8000/upload/api/ file@~/Projects/lms/manage.py course=3 name=name
  POST /upload/api/ HTTP/1.1
  Accept: */*
  Accept-Encoding: gzip, deflate
  Connection: keep-alive
  Content-Length: 577
  Content-Type: multipart/form-data; boundary=634ec7c7e89a487b89c1c07c0d24744c
  Host: localhost:8000
  User-Agent: HTTPie/0.9.2
  
  --634ec7c7e89a487b89c1c07c0d24744c
  Content-Disposition: form-data; name="course"
  
  3
  --634ec7c7e89a487b89c1c07c0d24744c
  Content-Disposition: form-data; name="name"
  
  name
  --634ec7c7e89a487b89c1c07c0d24744c
  Content-Disposition: form-data; name="file"; filename="manage.py"
  
  #!/usr/bin/env python
  import os
  import sys
  
  if __name__ == "__main__":
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
  
      from django.core.management import execute_from_command_line
  
      execute_from_command_line(sys.argv)
  
  --634ec7c7e89a487b89c1c07c0d24744c--
  
  HTTP/1.0 200 OK
  Allow: POST, OPTIONS
  Content-Type: application/json
  Date: Thu, 17 Dec 2015 16:55:44 GMT
  Server: WSGIServer/0.2 CPython/3.4.3
  Vary: Accept, Cookie
  X-Frame-Options: SAMEORIGIN
  
  {
      "data": {
          "course": "3",
          "name": "name"
      },
      "files": "&lt;MultiValueDict: {'file': [&lt;InMemoryUploadedFile: manage.py ()&gt;]}&gt;",
      "raw": {}
  }
  </code></pre>
  
  <p>Am I missing something here?  I am using HTTPIE to generate the requests here but the same behaviour exists with curl so I'm pretty sure that is not the problem.  I am using djangorestframework==3.3.0 and Django==1.8.4</p>
  
  <p>EDIT:</p>
  
  <p>It seems that <code>PUT</code>ing to the url (with an otherwise identical request) achieves the desired result:</p>
  
  <pre><code>$ http -v --form PUT http://localhost:8000/upload/api/ file@~/Projects/lms/manage.py course=3 name=name
  PUT /upload/api/ HTTP/1.1
  Accept: */*
  Accept-Encoding: gzip, deflate
  Connection: keep-alive
  Content-Length: 577
  Content-Type: multipart/form-data; boundary=98feb59a8abe4bfb95a7321f536ed800
  Host: localhost:8000
  User-Agent: HTTPie/0.9.2
  
  --98feb59a8abe4bfb95a7321f536ed800
  Content-Disposition: form-data; name="course"
  
  3
  --98feb59a8abe4bfb95a7321f536ed800
  Content-Disposition: form-data; name="name"
  
  name
  --98feb59a8abe4bfb95a7321f536ed800
  Content-Disposition: form-data; name="file"; filename="manage.py"
  
  #!/usr/bin/env python
  import os
  import sys
  
  if __name__ == "__main__":
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
  
      from django.core.management import execute_from_command_line
  
      execute_from_command_line(sys.argv)
  
  --98feb59a8abe4bfb95a7321f536ed800--
  
  HTTP/1.0 200 OK
  Allow: POST, PUT, OPTIONS
  Content-Type: application/json
  Date: Thu, 17 Dec 2015 18:10:34 GMT
  Server: WSGIServer/0.2 CPython/3.4.3
  Vary: Accept, Cookie
  X-Frame-Options: SAMEORIGIN
  
  {
      "data": {},
      "files": "&lt;MultiValueDict: {}&gt;",
      "raw": "&lt;QueryDict: {'name': ['name'], 'course': ['3'], 'file': [&lt;InMemoryUploadedFile: manage.py ()&gt;]}&gt;"
   }
  </code></pre>
  
  <p>So I could just use <code>PUT</code>.  That is however not ideal as the client does not control what the file is named or where it is located on the server.  <code>POST</code> is more appropriate in that sense.  In any sense, I don't see why <code>PUT</code> works when <code>POST</code> doesn't.</p>