MultiValueDictKeyError for django image File upload - python

I have spent a LOT of time trying to resolve this- Read Django docs, consulted forms but not got anything satisfactory. So please be patient here with me.
I am trying to do an upload of an Image file here from my html template.
This is my html form
<form id="tryOnPageForm" method="POST" enctype="multipart/form-data" action="/dummy/{{frame.slug}}/">
{% csrf_token %}
<input type="file" name="uploadFromPC" id="uploadFromPC" class="myButton" title="Upload From PC" value= "Upload from PC" onchange="uploadPC()" style="float:left;">
<input type="submit" id="Submit" class="myButton" value= "Done" style="display:none"><br><br>
</form>
The file upload happens properly an d I am able to see the uploaded image file in the HTML.
In my views.py,
def upload_image(request, frameslug):
frame= v.objects.get(slug=frameslug)
if request.method == 'POST':
form = ImageUploadForm(request.POST, request.FILES)
print "FILES", request.FILES
if form.is_multipart():
save_file(request.FILES['image'])
return HttpResponseRedirect('Successful')
else:
return HttpResponse('Invalid image')
else:
form = ImageUploadForm()
return render_to_response('dummy.html', {'form': form})
def save_file(file, path=''):
''' Little helper to save a file
'''
filename = file._get_name()
fd = open('%s/%s' % (MEDIA_ROOT, str(path) + str(filename)), 'wb')
for chunk in file.chunks():
fd.write(chunk)
fd.close()
and in my forms.py,
from django import forms
class ImageUploadForm(forms.Form):
image = forms.ImageField(label='Select a file', help_text='max. 20 megabytes')
When I run my code I get this error
MultiValueDictKeyError at /dummy/fr1234/
The print statement in my from my view.py shows this
FILES <MultiValueDict: {u'uploadFromPC': [<InMemoryUploadedFile: model4.jpg (image/jpeg)>]}>
and this is the traceback
Traceback:
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
112. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Work-Backup\LiClipse Workspace\vTryON_DJango_Integration\vTryON\views.py" in upload_image
189. save_file(request.FILES['image'])
File "C:\Python27\lib\site-packages\django\utils\datastructures.py" in __getitem__
301. raise MultiValueDictKeyError(repr(key))
Exception Type: MultiValueDictKeyError at /dummy/fr1234/
Exception Value: "'image'"
I am aware that the enctype should be multipart/form-data since I have read it in tutorials. ALso, i have not used any field in my models.py to store the uploaded image.Instead I want to directly save it to thr MEDIA_URL location.Might that be an issue?
Please help. This has held me up for a long time. Thanks in advance.

I was able to solve this(after spending a lot of time and with some help from my friends...)
I think the error
Exception Type: MultiValueDictKeyError at /dummy/fr1234/
Exception Value: "'image'"
was coming because request.FILES was unable to get the uploaded image from the user input, the reason being that the name of the user input file that I provided was wrong!!
It should have been request.FILES['uploadFromPC'] instead of request.FILES['image'] because that is the name that I had kept in my HTML.
<input type="file" name="uploadFromPC" id="uploadFromPC" class="myButton" title="Upload From PC" value= "Upload from PC" onchange="uploadPC()" style="float:left;">
That was a stupid error and a lot of time wasted to fix it.. :(
.. but ya, good learning.
I hope this helps somebody else who is trying to do something similar. Although, I would like it if somebody can explain to me the use of forms.py here.
Is it possible to do an user upload without forms.py?

I found that the error occurs when you submit the form without selecting the file. when a file is not selected then the input_name in your case image is u''. this gives the error as the dictionary has no such key.
i tried to find a way to try and except error but there is no such exception in python MultiValueDictKeyError

request.FILES['file1']
raises the multivaluedictkeyerror, so please check if you have the files under request.FILES like below -
if request.method == "POST" and 'file1' in request.FILES and 'file2' in request.FILES:
Don't use
if request.method == "POST" and request.FILES['file1']:
as it also raises error

Related

form.is_valid() always returns false perhaps issue with "This field is required" error

I am learning django. I am stuck with this problem.
The problem is that form.is_valid() always returns false.
I tried to debug and I think that the problem is because of "This field is required" error and I think that the field is file_name. I tried to resolve the issue but I am unable to do so.
Just to give a context of what I am trying to do -
I have created a form in which a user uploads a text file and selects a gender.
In the backend I want to save the name of the text file along with the gender in a model. The purpose of doing this is because when multiple users will use the application, I should know which user selected what gender so that I can produce the desired output.
Here is the link to my git repository -
git repository
As I already said I am new to django and some help will be appreciated.
Your fields in form are fields = ['file_name','gender'] and in the template you have
<label for="myfile"> <b> Select a file: </b> </label> <br/>
<input type="file" name="document"> <br/><br/>
<br/><br/>
{{ form.gender }}
... fields document and gender, no file_name. Add {{ form.file_name }} to the template or, if you want to stick to manually writing code for input, file input with a name file_name. Input names need to match field names in form.
Also, read this: Working with forms.
I think you are not saving the form. In your views line 24 you have
if request.method == 'POST':
form = TranscriptForm(request.POST)
return HttpResponse(str(form.errors))
If you are posting you will always return there,therefore there is no check for is_valid().
Same as line 60:
context = {'form': TranscriptForm()}
return render(request, 'tutorial/upload.html', context)
you havent accessed/saved the form yet for it to be valid

Not able to handle multiple post request on the same page

I have code which should handle multiple post request on the same page. It has two button in the HTML page inside a single form. It is taking the post value from first button, but not the second. I have no idea why, when I include the second button and click on first, it says the second button is not found. Can anyone please help me solve this issue?
index.html
<input type="submit" style="background-color:#FFFF66;color:black;width:150px; height:40px;" name="ServerDetails" value="ServerDetails"/>
<br><br>
<input type="submit" style="background-color:#FFFF66;color:black;width:150px; height:40px;" name="GenerateFile" value="GenerateFile"/>
views.py
if request.method == 'POST':
if request.POST['ServerDetails']:
print("Inside Server Details")
if request.POST['GenerateFile']:
filename = request.POST['patchconfigofpg3']
print(filename)
models.py
class course(models.Model):
patchconfigofpg3 = models.CharField(max_length=100)
When I click on the first button it is throwing me the below error:
just change
if request.POST['ServerDetails']:
to
if request.POST.get('ServerDetails',False):
and do same for other button
The problem is you write request.POST['ServerDetails'] and request.POST['GenerateFile']. Bascially you try to access the key on the QueryDict but this key does not exist giving you an error. Instead you should use the in operator:
if request.method == 'POST':
if 'ServerDetails' in request.POST:
print("Inside Server Details")
if 'GenerateFile' in request.POST:
filename = request.POST['patchconfigofpg3']
print(filename)

why do I get "FileNotFoundError" when doing fileupload with Django?

I am writing a file upload page with Django/Python. I get this error:
FileNotFoundError: [Errno 2] No such file or directory: '48.png'.
Here is the relevant part of the view, which handles the upload:
`if request.method == 'POST':
form = myform(request.POST, request.FILES)
if form.is_valid():
print("FORM VALID")
f = request.FILES['thefile']
print("f:" + f.name)
print(pref+'/'+str(f))
open(f.name, 'rb')
else:
print('FORM NOT VALID')
Things go wrong in the open(f.name statement. The form is in a template:
<form method="post" action="/dataset_storage_upload/{{ pk }}/{{pid}}/" name="submit" enctype="multipart/form-data">
{% csrf_token %}
{{ theForm.as_p }}
<button type="start_upload" value="Submit" onclick="document.upload.submit() ">Upload</button>
</form>
and this is the form:
class myform(forms.Form):
thefile = forms.FileField()
I have this information in the console
FORM VALID
f:48.png
/17/3/48.png
(/17/3 is the prefix)
In the Traceback, in the browser, under local vars, I have this:
pref '/17/3'
mylist[]
f <InMemoryUploadedFile: 48.png (image/png)>
pk '17'
form <myform bound=True, valid=True, fields=(thefile)>
request<WSGIRequest: POST '/dataset_storage_upload/17/3/'>
I think this tells me that there is a file 48.png in memory. So why is it not there when I open it?
Many thanks for your attention.
It's only there in memory, not on the actual filesystem. Django File objects provide a wrapper around both real files, and in-memory files.
For example, if you were handling a file that was coming from a FileField on some model, what you're doing would work, but the file you're handling doesn't yet exist on the system.
If you want to read the file in your view, you can just call File.read:
f = request.FILES['thefile']
contents = f.read()
By default, if an uploaded file is smaller than 2.5 megabytes, Django
will hold the entire contents of the upload in memory. This means that
saving the file involves only a read from memory and a write to disk
and thus is very fast.
I changed f.open( into f.read( and now it works perfectly. For completeness: My goal is to store the uploaded file in S3, so that now I do
s3.Object('mybucket', str(pk)+'/'+str(p)+'/'+str(f)).put(Body=f.read(),Metadata={'project': '17','dataset':'3','filename':str(f)})
and this works.

Python/Django - using a view method on an upload file

I have this view:
def index(request):
file = open("SK ✌😜✌.txt", encoding="UTF-8")
data = file.read()
file.close()
lines = data.split("\n")
...More code...
In this view i open a file from the very first moment the app starts and i do some work on the file, is a story, and when i start the server and go to http://127.0.0.1:8000/(Name Of The App), i see all the work that i have done on that file.
What i want to do is to do that same work, starting with the reading of the file, BUT i want to do that with the file that the user uploads in that moment. I have this that i took from bootstrap:
<div class="form-group">
<label for="exampleInputFile">File input</label>
<input type="file" id="exampleInputFile">
</div>
I guess i have to use in some way the id of the input but i`m not really sure how to pass this file that the user uploads in the ui to the method that i have in my views.py
Any help will be really appreciated
You need to have a name attribute in your <input> template code.
<input type="file" id="exampleInputFile" name="some_file">
Then to access the file in your view, you need to use request.FILES attribute.
As per the Django docs on HttpRequest.FILES attribute:
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.
Your code should be something like:
def index(request):
if request.method=="POST":
uploaded_file = request.FILES['some_file'] # get the uploaded file
# do something with the file
Note: request.FILES will only contain data if the request method was POST and the <form> that posted to the request had enctype="multipart/form-data. Otherwise, FILES will be a blank dictionary-like object.

How do I redirect after login using django while passing variables and saving to a database?

I am trying to allow a user to favorite a video while they're signed out. I'm using #login_required to force the user to sign in, have the video saved to their account, and then redirect back to the page they were on. I am getting an error saying
UnboundLocalError at /loggedout_fav/
local variable 'video' referenced before assignment
on the return line under loggedout_fav. I put a print statement in the view but nothing is printing to the console either. Any advice on how to fix it?
html
<form method = 'post' action = '/loggedout_fav/'> {% csrf_token %}
<input type="hidden" value="{{video}}" name = "video_add_loggedout"/>
<input type='submit' value='Login to plate this video'/>
</form>
url
url(r'^loggedout_fav/', 'loggedout_fav'),
view
def loggedout_fav(request):
if 'video_add_loggedout' in request.POST:
video = request.POST['video_add_loggedout']
print video
print 'test'
try:
s = Everything.objects.get(profile = request.user, video = request.POST['video_add_loggedout'], playlist = 'Favorites', platform = 'youtube')
print "already exists"
except:
p = Everything(profile = request.user, video = request.POST['video_add_loggedout'], playlist = 'Favorites', platform = 'youtube')
p.save()
return HttpResponseRedirect(reverse('reserve.views.trending_video_player', kwargs={'author':'youtube', 'video':video}))
def trending_video_player(request,author,video):
...
You used 'id' instead of 'name' ! So this is never True:
if 'video_add_loggedout' in request.POST:
And video is never set, so it chokes on (you should have posted the stacktrace BTW, I had to reverse that):
return HttpResponseRedirect(reverse('reserve.views.trending_video_player', kwargs={'author':'youtube', 'video':video}))
First things first you could fix your Python, like this:
def loggedout_fav(request):
if 'video_add_loggedout' not in request.POST:
return HttpResponseBadRequest()
video = request.POST['video_add_loggedout']
try:
s = Everything.objects.get(profile = request.user, video = request.POST['video_add_loggedout'], playlist = 'Favorites', platform = 'youtube')
print "already exists"
except:
p = Everything(profile = request.user, video = request.POST['video_add_loggedout'], playlist = 'Favorites', platform = 'youtube')
p.save()
return HttpResponseRedirect(reverse('reserve.views.trending_video_player', kwargs={'author':'youtube', 'video':video}))
Of course, fix your HTM too, this:
<input type="hidden" value="{{video}}" id = "video_add_loggedout"/>
Should be:
<input type="hidden" value="{{video}}" name="video_add_loggedout"/>
Save the values to the session. https://docs.djangoproject.com/en/dev/topics/http/sessions/
Make sure you grab the values in the session before logging the user in so you won't lose them.
I believe what jpic said might well be the problem. I post a separate answer to clarify the problem: The UnboundLocalError is a python error meaning that somewhere in your code you access a variable prior to defining it.
In your 'loggedout_fav' view code, I see you attempt to access the 'video' variable in the last line. When the if 'video_add_loggedout' in request.POST statement is not True (and therefore the nested block not executed), 'video' variable will not be initialized and this Exception will be raised. Practically this means that you attempt to access your view without posting a 'video_add_loggedout' variable. I would reorganize the view as follows:
def loggedout_fav(request):
try:
Everything.objects.get_or_create(profile=request.user, video=request.POST['video_add_loggedout'], playlist='Favorites', platform='youtube')
except KeyError:
#do something when the variable is not set. eg:
return HttpResponseBadRequest()
return HttpResponseRedirect(reverse('reserve.views.trending_video_player', kwargs={'author':'youtube', 'video':request.POST['video_add_loggedout']}))
The above also demonstrates how you can use the get_or_create method to clean up your code a little.

Categories

Resources