9

I'm trying to write form to upload a file with Django. The admin form works just fine, but the problem is that after I click submit on my form, the form loses the file that I selected (filename disappears and 'No file chosen' appears next to 'Choose File' button), and the view won't validate the form because the file is missing. My form/view/file handler look just like the django example.

forms.py

class AttachForm(forms.ModelForm):
    class Meta:
            model = Attachment
            exclude = ('insp', 'contributor', 'date')

views.py

def handle_uploaded_file(f):
    destination = open('some/file/name.txt', 'wb+')
    for chunk in f.chunks():
        destination.write(chunk)
    destination.close()

def attach(request, insp_id):
    if request.method == 'POST':
            form = AttachForm(request.POST, request.FILES)
            if form.is_valid():
                    handle_uploaded_file(request.FILES['file'])
                    f = form.save(commit=False)
                    f.contributor = request.user
                    f.insp = insp_id
                    f.save()
                    return HttpResponseRedirect(server + '/inspections/' + str(insp_id) + '/')
    else:
            form = AttachForm()
    return render_to_response('attach.html', locals(), context_instance=RequestContext(request))

models.py

class Attachment(models.Model):
    insp = models.ForeignKey(Inspection)
    contributor = models.ForeignKey(User, related_name='+')
    date = models.DateTimeField()
    title = models.CharField(max_length=50)
    attachment = models.FileField(upload_to='attachments')
    def __unicode__(self):
        return self.title
    def save(self):
        if self.date == None:
            self.date = datetime.now()
        super(Attachment, self).save()
    class Meta:
        ordering = ['-date']

attach.html

{% extends "base.html" %}

{% block title %}Add Attachment{% endblock %}

{% block content %}
<h2>Attach File: Inspection {{ insp_id }}</h2>
<p>This form is used to attach a file to an inspection.</p>
<form action="." method="POST" autocomplete="off">{% csrf_token %}
    <table cellspacing="10" cellpadding="1">
        {% for field in form %}
            <tr>
            <th align="left">               
                {{ field.label_tag }}:
            </th>
            <td>
                {{ field }}
            </td>
            <td>
                {{ field.errors|striptags }}
            </td>
        </tr>
        {% endfor %}
        <tr><td></td><td><input type="submit" value="Submit"></td></tr>
    </table>
</form>
{% endblock %}

Any ideas of what I could be doing wrong?

3
  • 2
    Could you post the template code too? One important thing to remember is: "Note that request.FILES will only contain data if the request method was POST and the <form> that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty." Commented Oct 5, 2011 at 16:04
  • as a side note, you can use the auto_now and auto_add_now (link to docs) properties for DateTimeFields so that you don't need to overide the save method. auto_now updates the date every save and auto_add_now is just the creation date, Commented Oct 5, 2011 at 16:05
  • 2
    Adding enctype="multipart/form-data" to the form tag fixed that problem, but now it's throwing a MultiValueDictKeyError with description "Key 'file' not found in <MultiValueDict: {u'attachment': [<InMemoryUploadedFile: image.png (image/png)>]}>" Commented Oct 5, 2011 at 16:18

1 Answer 1

7

Change this...

handle_uploaded_file(request.FILES['file'])

To this...

handle_uploaded_file(request.FILES['attachment'])

The file is stored in the POST data with the name of your field.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.