64

Trying to use a very simple form to upload a file into a new class instance. I am expecting to have both files in request.FILES but it's empty. I am on the bundled dev server.

Been stuck here and went through all related questions.

wayfinder_map.media_file = request.FILES['media_file'] 

generates

MultiValueDictKeyError: "Key 'media_file' not found in MultiValueDict: {}>"

model

class WayfinderMap(models.Model):
    """ Way-finding Map Config"""


    media_file = models.FileField(upload_to="maps", null=True, blank=True) 
    wall_file = models.FileField(upload_to="maps_data", null=True, blank=True) 

view

@login_required
def create_map(request, form_class=WayfinderMapForm, template_name="wayfinder/map/create.html"):
wayfinder_map_form = form_class(request.user, request.POST or None, request.FILES)

    if wayfinder_map_form.is_valid():
        wayfinder_map = wayfinder_map_form.save(commit=False)
        wayfinder_map.media_file = request.FILES['media_file']
        wayfinder_map.data_file = request.FILES['data_file']
        wayfinder_map.creator = request.user
        wayfinder_map.save()
    return HttpResponseRedirect(wayfinder_map.get_absolute_url())

return render_to_response(template_name, {
    "wayfinder_map_form": wayfinder_map_form,
}, context_instance=RequestContext(request))

template

<form enctype="multipart/form-data" class="uniForm" id="wayfinder_map_form" method="POST" action="">
        <fieldset class="inlineLabels">
            {{ wayfinder_map_form|as_uni_form }}
            <div class="form_block">
                <input type="hidden" name="action" value="create" />
                <input type="submit" value="{% trans 'create' %}"/>
            </div>
        </fieldset>
    </form>
BoJack Horseman
  • 4,406
  • 13
  • 38
  • 70
philgo20
  • 6,337
  • 6
  • 34
  • 43
  • i think the answers to this similar question will help you out : http://stackoverflow.com/q/5895588/1037459 –  Nov 09 '11 at 11:05
  • Besides `enctype="multipart/form"` missing, another reason can ben that the file input field doesn't have a name. – Herbert Dec 20 '22 at 12:45

6 Answers6

241

old question, but somebody might still find this useful.

In order to have your <input type=file> files uploaded and showns in request.FILES, your form MUST contain enctype="multipart/form-data", eg:

<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<button type="submit">{% trans 'Submit' %}</button>
</form>

otherwise your files will not be uploaded and your request.FILES will be empty.

BTW That's a common solution to a common error. Nevertheless, I still found myself in a situation with an empty FILES (and the file in the POST) when everything else was looking OK. I have the feeling it was a size limit but did not want to spend more time debugging, and just used request.raw_post_data. If ever somebody falls on this issue please add a comment (including precise django version!) and I'll try to debug more deeply.

Stefano
  • 18,083
  • 13
  • 64
  • 79
4

It seems as request.FILES is not necessary in this case (good thing cause it's empty ...)

I modified this line

wayfinder_map.media_file = request.FILES['media_file'] 

for

wayfinder_map.media_file = wayfinder_map_form.cleaned_data['media_file'] 

and it works. Not sure what the right way to do thing though... –

Facundo Casco
  • 10,065
  • 8
  • 42
  • 63
philgo20
  • 6,337
  • 6
  • 34
  • 43
3

I know this is an old question, but it is the first result on google for "django request.file empty" so I would like to add a potential solution after searching for two days:

If you submit your files through ajax, make sure to send your form via formData() instead of form.serialize()

see also here: Django JQuery Ajax File Upload

Jakob Müller
  • 91
  • 1
  • 8
2

The problem for me was that I am missing the "name" attribute for the file input.

Mohammed
  • 134
  • 6
1

I found that If you put put the form in a content block then it seems to work

    {% block content %}
<form enctype="multipart/form-data" class="uniForm" id="wayfinder_map_form" method="POST" action="">
        <fieldset class="inlineLabels">
            {{ wayfinder_map_form|as_uni_form }}
            <div class="form_block">
                <input type="hidden" name="action" value="create" />
                <input type="submit" value="{% trans 'create' %}"/>
            </div>
        </fieldset>
    </form>
{% endblock %}
0

I think your troubles may lie in assigning data to a form without first verifying the the request is POST

@login_required
def create_map(request, form_class=WayfinderMapForm, template_name="wayfinder/map create.html"):
  if request.method=='POST':
    wayfinder_map_form = form_class(request.user, data=request.POST, files=request.FILES)

    if wayfinder_map_form.is_valid():
      #save your data
      return HttpResponseRedirect(wayfinder_map.get_absolute_url())

  else:
    wayfinder_map_form=form_class(request.user)

 return render_to_response(template_name, {"wayfinder_map_form": wayfinder_map_form,}, context_instance=RequestContext(request))
czarchaic
  • 6,268
  • 29
  • 23
  • been using it this way with no problem so far. might be a good check (if necessary) but it certainly does not solve the problem as request.FILES is still empty – philgo20 Jan 06 '10 at 05:59
  • What do you mean 'no problems so far'? Did this work properly before? Can you post your form class? – czarchaic Jan 06 '10 at 14:08
  • What I mean is that I've been using forms with no problem, as long as I don't have to use request.FILES, without checking if the method is POST. Does tying request.POST to data in the instantiation of the class like you do could help ? I'll try that and post my form. – philgo20 Jan 07 '10 at 14:22