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:

Check that you have added enctype property into form tag.

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

Solution 2:

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.