14
votes

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?

3
Looks like your html form is missing the name attributes in your input fields, try like <input type="file" id="grade_csv" name="file"/>Jingo
A few things that are suspicious to me. Your form inputs are missing name attributes. You are sub-classing forms.Form but have a Meta class indicating you want forms.ModelForm. If you intend to use a model form you don't need to instantiate a Document object because the form does this for you.Scott Woodall
Genius--thanks! I'd be happy to accept as the answer if you submit it as one...user
It's almost certainly the missing name attributes. That's where the keys for the POST data come from, not the IDs.Peter DeGlopper
name attributes fixed it...not sure I understand completely Scott's comment about model forms (I was trying to follow the Django example on forms). Does that mean I don't need the class Meta: tag?user

3 Answers

20
votes

Check that you have added enctype property into form tag.

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

2
votes

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.

1
votes

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.