1

Hi I am learning Django for a project and I am trying to upload a file along with a on option in dropdown list through a form using POST. Here are my files:

views.py

from __future__ import unicode_literals

from django.shortcuts import render
from django.http import HttpResponse

from .forms import UploadFileForm

# function to handle an uploaded file.
from save_uploaded_file import handle_uploaded_file


def index(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return render(request, 'viewer_app/display_image.html')
        else:
            print('error')
            return render(request, 'viewer_app/index.html', {'form': form})
    else:
        return render(request, 'viewer_app/index.html')

forms.py

from django import forms

class UploadFileForm(forms.Form):
    file = forms.FileField()
    displayType = forms.ChoiceField(widget=forms.Select(), required=True)

save_uploaded_file.py

def handle_uploaded_file(f):
    with open('static/viewer_app/temp.exr', 'wb+') as recieved_exr:
        for chunk in f.chunks():
            recieved_exr.write(chunk)

index.html

<div id="formDiv" style="display:none;" class="form" >

    <form  method="post" enctype="multipart/form-data" class="form-style">

        <label for="browse">Upload file</label>
        <input type="file" value="Browse" id="brow" /><br></br>

        <label for="display">Display type</label>
        <select id="display-type" name="display">
            <option id="RGB1" value="RGB1">RGB1</option>
            <option id="RGB2" value="RGB2">RGB2</option>
            <option id="RGB3" value="RGB3">RGB3</option>
            <option id="RGB4" value="RGB4">RGB4</option>
        </select><br></br>

        <input type="submit" value="Show file" id="showimage"/><br></br>
        {% csrf_token %}        

    </form>
</div>

So, after I run the server to display the page and I select the upload and click submit, it doesn't upload and save the file and in the terminal I see the "error" text in the terminal which is displayed due to from.is_valid() not being true.

I tried to add {{ form.errors }} {{ form.non_field_errors }} to the html file but I still don't know exactly what is that I am doing wrong.

programmingIsFun
  • 1,057
  • 2
  • 11
  • 20
  • 1
    Try writing "print(form._errors)" in the "else:" block of "form.is_valid():" to display the exact error in the console. Maybe that will help. Or can you provide us with the what it displays in the console? – Shivam Sharma Aug 07 '17 at 21:52
  • I added the print(form._errors) and the error message I get is:
    • displayType
      • This field is required.
    • file
      • This field is required.
    [07/Aug/2017 22:07:25] "POST /viewer_app/ HTTP/1.1" 200 4467
    – programmingIsFun Aug 07 '17 at 22:08
  • 1
    As you can see that 2 fields are required and your form isn't bound to them. Things that you can do: 1) Make sure that those two are the only fields inside your form. 2) You can write print(request.POST) in "if request.method == 'POST':" block to make sure that data is at least coming from the index.html which will narrow the error to Django. – Shivam Sharma Aug 07 '17 at 22:16
  • So as you can see in my form file, those are the only two fields I have in the form. After adding print(request.POST), I got a list which seems like the data is coming from the index.html: . Now, I am not sure which part in my django is having a problem. – programmingIsFun Aug 07 '17 at 22:24

1 Answers1

1

Also I can see the absence of name attributes inside your <input> tag and a potentially wrong name attribute inside your <select> tag. You should put the exact name of the field inside your html 's name attribute for the form to get bounded. Same goes for the <select> tags.

Try putting:

<input type="file" value="Browse" id="brow" name="file"/>

and

<select id="display-type" name="displayType">

and probably your problem will be solved. If I may suggest, why aren't you using the standard django template form tags, Such as {{ form.as_p }} ? These methods are quite handy and will also handle the errors successfully. You should try using them. check them here

EDIT You haven't given any choices attribute to you ChoiceField in your forms.py. Make sure to give a attribute choices as a tuple to your ChoiceField. It can be done as:

#import ugettext_lazy
from django.utils.translation import ugettext_lazy as _

#inside your form class
class UploadFileForm(forms.Form):
    CHOICES = (
        ('RGB1', _('RGB1')),
        ('RGB2', _('RGB2')),
        ('RGB3', _('RGB3')),
        #And so on
    )
    #First option in the tuple is stored in db. Second is displayed in Forms.
    displayType = forms.ChoiceField(widget=forms.Select(), required=True , choices = CHOICES)
    file = forms.FileField()

EDIT 2:

Get the file url as below,

from django.contrib.staticfiles.templatetags.staticfiles import static

url = static('viewer_app/temp.exr')
#See if temp.exr exists prior to this. Otherwise create a file manually  or through python.

Then open the file by supplying this url.

Again I would recommend you to check ModelForms. They'll completely eliminate the need to write files this way.

Hope it helps. Thanks.

Shivam Sharma
  • 901
  • 1
  • 6
  • 12
  • I added the names as you suggested, but then I get this error:
    • displayType
      • Select a valid choice. RGB1 is not one of the available choices.
    . But if you look at the html code RGB1 is one of the options in the list.
    – programmingIsFun Aug 07 '17 at 23:54
  • Yeah I helped with that part but then I get this error: IOError at /viewer_app/ [Errno 2] No such file or directory: 'static/viewer_app/temp.exr'. If you look at the python code for handle_uploaded_file, temp.exr is the filename I am opening to write to, so I don't get the "no such file" error. – programmingIsFun Aug 08 '17 at 00:19
  • I recommend you open the file using "from django.contrib.staticfiles.templatetags.staticfiles import static". Giving a url like that might be causing a problem. I've explained it more clearly in another EDIT. – Shivam Sharma Aug 08 '17 at 00:28
  • I tried that suggestion and used the static import in the save_uploaded_file.py, but it still gives me the same error. – programmingIsFun Aug 08 '17 at 22:15
  • I tried writing a file the way you are writing and it worked alright. It works even if you don't have a file created already( with open() ) does that for you. The only time I stumbled upon an error was when the directory I wanted to access through open wasn't created at all. The error I got was " [Errno 2] No such file or directory " ; traced back to the line " with open('static/viewer_app/temp.exr', 'wb+') as recieved_exr: " . Tell me if you're getting an error different from this. – Shivam Sharma Aug 09 '17 at 04:11
  • Also, have you added a name attribute inside " " yet? It should look like " " – Shivam Sharma Aug 09 '17 at 04:13
  • Actually the problem ended up being something else. I found it in this thread in answer 2: https://stackoverflow.com/questions/10637352/flask-ioerror-when-saving-uploaded-files/20257725#20257725 – programmingIsFun Aug 10 '17 at 19:00