I have already consulted lots of forums and I can't get an answer. I have installed a file upload in my Django app to save data into my server. But it does not work. Instead, it raises a MultiValueDictKeyError. I guess the problem is that there is not request.FILES (because it raises an error in request.FILES mentions), so the file upload is not working. This is my views.py:
def list_files(request, phase_id):
phase = get_object_or_404(Phase, pk=int(phase_id))
if request.method == 'POST':
#form = DocumentForm(request.POST, request.FILES)
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'], phase = phase_id)
newdoc.save()
doc_to_save = request.FILES['docfile']
filename = doc_to_save._get_name()
fd = open(settings.MEDIA_URL+'documents/'+str(filename),'wb')
for chunk in doc_to_save.chunks():
fd.write(chunk)
fd.close()
return HttpResponseRedirect(reverse('list_files'))
else:
form = DocumentForm()
documents = Document.objects.filter(phase=phase_id)
return render_to_response('teams_test/list_files.html',{'documents': documents, 'form':form, 'phase':phase}, context_instance = RequestContext(request)
)
The document form in forms.py:
class DocumentForm(forms.ModelForm):
docfile = forms.FileField(label='Select a file', help_text='max. 42 megabytes')
class Meta:
model = Document
The class document in models.py:
class Document(models.Model):
docfile = models.FileField(upload_to='documents')
phase = models.ForeignKey(Phase)
Finally, my html code:
{% extends "layouts/app.html" %}
{% load i18n user %}
{% block title %}{% trans "Files list" %}{% endblock %}
{% block robots %}noindex,nofollow{% endblock %}
{% block page%}
<div id="page" class="container">
<div class="header prepend-2 span-20 append-2 last whiteboard">
<h2 style="margin-left:-40px">{{ phase.name }} files</h2>
{% if documents %}
<ul>
{% for document in documents %}
<li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
<form action="{% url list_files phase.id %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input id="file" type="file" />
<input id="submit" type="submit" value="Upload file" />
</form>
</div>
</div>
{% endblock %}
My traceback says:
Exception Type: MultiValueDictKeyError
Exception Value: "Key 'docfile' not found in <MultiValueDict: {}>"
my_dir/views.py in list_files
newdoc = Document(docfile = request.FILES['docfile'], phase = phase_id)
And my QueryDict is empty:
POST:<QueryDict: {u'csrfmiddlewaretoken': [u'UZSwiLaJ78PqSjwSlh3srGReICzTEWY1']}>
Why? What am I doing wrong?
Thanks in advance.
You need to change multipart/form_data
to multipart/form-data
- that's why request.FILES
is empty: the form isn't sending things in the way Django expects due to the typo. [EDIT: this has now been done]
Update 1: Also, rather than directly access request.FILES, try relying on the modelform's default behaviour, as then it'll have been handled as an upload appropriately. ie, newdoc = form.save()
should do all you need, from a quick look at it - is there a particular reason you manually saving the file when the modelform can do that for you?
Update 2: Ah, look: you're not assigning a name to your file upload element
From the docs:
HttpRequest.FILES A dictionary-like object containing all uploaded files. Each key in FILES is the name from the
<input type="file" name="" />
. Each value in FILES is an UploadedFile
So, you need to change
<input id="file" type="file" />
to
or, for default Django convention
<input id="id_docfile" type="file" name="docfile"/>
Indeed, it's usually better to use the Django form to render the actual field, even if you've moved beyond the whole {{form.as_p}}
approach:
{{form.docfile}}
PS. if you've not read them fully, I heartily recommend taking the time to go through all of the forms documentation
Modify Post method to
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With