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.