'request.FILES always empty on file upload

I am totally stumped on this, and must be doing something incredibly stupid. I am trying to simply upload a file on a Django project. The problem seems to be that NO form data is getting passed through to the server--only the csrf token. I am running Django 1.5.1, python 2.7, virtualenv, on a Mac, and using the built-in Django development server.

My HTML form is:

{% load url from future %}

<form enctype="multipart/form-data" method="POST" action="{% url 'showreport' %}">
    {% csrf_token %}
    <label>Upload grade csv file: </label>
    <input type="hidden" id="testing" value="maybe" />
    <input type="file" id="grade_csv" />
    <input type="submit" value="Generate Report" />
</form>

My model:

from django.db import models

class Document(models.Model):
file = models.FileField(upload_to='/media/', blank=True, null=True)

My forms.py:

from django import forms
from .models import Document

class DocumentForm(forms.Form):
"""
to handle uploading grades csv file
"""
class Meta:
    models = Document

My views.py:

def report(request):
"""
Process the CSV file to remove inactive students
Manipulate to get right JSON format
Chart the results
"""
if request.method == 'POST':
    form = DocumentForm( request.POST, request.FILES )
    if form.is_valid():
        newfile = Document( file = request.FILES['file'] )
        newfile.save()

        classdata = {}
        studentdata = {}

        return render( request, 'report/showreport.html', { 'classdata': classdata, 'studentdata': studentdata } )
else:
    form = UploadFileForm()

return render( request, 'report/index.html', { 'form': form })

I have spent several hours searching for a solution, but nothing seems to work. I have the enctype set correctly (I think), I am using input type 'submit' for the form, and I am binding the form data to my model (doesn't matter, since request.FILES is empty). I also tried using a direct url in my form action (action='/report/showreport/') per this Django newbie page, but that didn't make a difference. As far as I can tell, there are no other scripts binding to the form submit action and overriding the default action.

I also realize that the code above should most likley be request.FILES['grades_csv'] to match the form's input id...yet that also doesn't matter yet, since request.FILES is empty.

In trying to debug, I have set a pdb trace right before the if request.method == "POST" in my view. Using the console, I can see that my request.POST does not include my hidden "testing" input, and that request.FILES is empty. When I run this in a browser, it just returns me to my form page, essentially saying my form is invalid. My pdb results are here:

(Pdb) request.FILES
(Pdb) <MultiValueDict: {}>
(Pdb) request.POST['testing']
(Pdb) *** MultiValueDictKeyError: "Key 'testing' not found in <QueryDict: {u'csrfmiddlewaretoken': [u'0tGCChxa3Po619dCi114Sb9jmWRt82aj']}>"
(Pdb) request.POST
<QueryDict: {u'csrfmiddlewaretoken': [u'0tGCChxa3Po619dCi114Sb9jmWRt82aj']}>

If I try to access request.FILES in my views.py without checking if the form is valid, I get this error:

"Key 'file' not found in <MultiValueDict: {}>"

I am stumped and appreciate any help on why I cannot get this to work--it seems like it should be simple. I can manually create and write to files within my project directory using pdb, so I don't think permissions are the problem...the problem is in the form?



Solution 1:[1]

I hope that you have already solved this issue. I had the exactly same issue and I found out I had no name prop in input tag

<input type="file" id="grade_csv" /> that is your input.

if it doesn't have name, django won't take it. So add name prop then it will work well.

Solution 2:[2]

Check that you have added enctype property into form tag.

Example from official docs: <form enctype="multipart/form-data" method="post" action="/foo/">

Solution 3:[3]

I had this problem too and was puzzling over it for a while. My error was the same -- that I was missing necessary fields on the input field.

In order to see what the actually required fields are, a very nice thing to do is, in this case:

from base.forms import DocumentForm ## or put whatever the name is of the app, which is unspecified in the question
print DocumentForm()

This will print the html that you need, including all the tags that this object requires. Very neat functionality which I missed the first time, but which is outlined in the docs.

Solution 4:[4]

I just encountered a weird bug where it shows as empty when I print it out:

print(request.FILES)
# Prints <MultiValueDict: {}>

If I load up a debugger and actually inspect the object though, it's not empty and contains the data I was expecting. This is the same exact object in both cases. The debugger shows FILES as populated, then when I continue, print shows it as empty.

So, if you're like me and you wanted to poke at the object first to understand it a bit, maybe don't rely on MultiValueDict's string representation. I can't explain the source of the bug though since MultiValueDict is just subclass of dict and uses dict's __str__.

Solution 5:[5]

<input type="file" id="grade_csv" name="name" />

You have to add name to your input field.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ???
Solution 2 Evgeney Kuznetsov
Solution 3 gabe
Solution 4
Solution 5 aksh_sharma