1

I am attempting to create code that allows users to input a photo and have that photo save to the folder '/home/HassanSherien/mysite/Shape_Image'. I have followed the steps given in the below link but I keep getting an error that states "Not Found, the requested URL was not found on the serves. if you entered the URL manually, please check your spelling and try again."

Python:

 import os
 from flask import Flask, request, redirect, url_for
 from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/home/HassanSherien/mysite/Shape_Image'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def upload_file():
    if request.method == 'POST':
    if 'file' not in request.files:
        flash('No file part')
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        flash('No selected file')
        return redirect(request.url)
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

HTML:

<form action="myform.cgi"> 
<input type="file" name="fileupload" value="fileupload" 
id="file`upload"> 
<label for="fileupload"> Select a file to upload</label>
 <br>
<input type="image" src="/wp-content/uploads/sendform.png" 
alt="Submit" width="100"> 
</form>

I am also given an error on the line if file and allowed_file(file.filename): that says "undefined name 'allowed_file'"

Upload image in Flask

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
Cherry
  • 33
  • 6
  • I'd suggest going through a basic Flask tutorial to learn how to specify URLs before trying to write this. This one would be a good start: https://blog.pythonanywhere.com/169/ – Giles Thomas Nov 22 '19 at 17:24
  • Thank you! Also, if I did have a followup question after this, do I comment here or should I make a new thread? @GilesThomas – Cherry Nov 22 '19 at 18:21
  • Is your code trying to do a GET on the image before its fully uploaded? do you have GET http routes defined for getting the file after its uploaded? Putting a file on the server isn't enough - your service needs to securely serve them up. Also, can you state if you've debugged the code and what you've verified on the server side? I.E. is the file getting saved? Or is the method never getting called? Is the POST giving you a 404 before or after uploading or is it something else? Do you have your web-console open and checking the calls that are taking place? Thanks for any more information adds – TheJeff Nov 22 '19 at 18:57
  • No the photo uploads fine but it is the second I hit submit is when I get the error message. The file is not being saved for the folder that I have set up to have these photos enter in is empty. Ido have a web-console open but I am unsure how I would check the calls that are taking place! I feel like my issue is that between my python and my html code, there is no indication that well the submit button that shows up on my html code is the button that should trigger that save in my python code if that makes sense. @TheJeff – Cherry Nov 23 '19 at 19:36

1 Answers1

2

You haven't assigned a route to your upload_file function. This should be done on the line immediately above the function definition:

@app.route('/upload', methods=['POST'])
def upload_file():
    # rest of your code

Also you'll need to make the form's action correspond to this URL:

<form action="/upload" method='POST'>

In Flask templates you can generate this URL automatically, based on the function name:

<form action="{{ url_for('upload_file') }}" method='POST'>

Also the only input fields in your form should be:

<input type="file" name="file" id="file_upload" /> 
<input type="submit />

Notice I've set name="file" which corresponds to what your Python code accepts. See this answer I've just posted for why this is. The offical docs on this are a bit confusing as they reuse the term 'file' in multiple places, which I think confuses people, especially new-comers.


I am also given an error on the line if file and allowed_file(file.filename): that says "undefined name 'allowed_file'"

Sounds like you haven't defined that function as per the docs:

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

EDIT as per comment:

now my website will allow people to upload photos and it will automatically submit (since despite there being no submit button the code knows to right after something is uploaded submit it)

Sorry: You need a second input tag for the submit button: just <input type='submit' /> towards the end of the form.

Once the user has selected the file they wish to upload, they then click this button and a POST request is sent to the server with the data.

to url_for('upload_file') which was '/home/HassanSherien/mysite/Shape_Image' in my case.

When the form is actually rendered (prior to any upload activity) the form's action attribute will be the return value of {{url_for('file_upload')}} This will be /upload (as set in the @app.route line). This makes the form submit to: http://example.com/upload. Don't confuse this with the path entered in UPLOAD_FOLDER which is server side.

In the code which handles the upload the following line joins the path specified as UPLOAD_FOLDER to the value of filename:

file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

To make this a bit easier to read, it's the same as:

full_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(full_path)

That second line is you calling the save method of the file object, providing the full path as the argument. This literally saves the file to disk.

If you're finding that this isn't happening, then check the server console as you may need to set directory permissions, etc.

This function should also return something like a redirect to someplace else on the site.

v25
  • 7,096
  • 2
  • 20
  • 36
  • Thank you so much for taking the time to walk this issue through with me! I am indeed a newcomer but I am motivated to learn haha. Although, I am confused about one part. So basically now my website will allow people to upload photos and it will automatically submit (since despite there being no submit button the code knows to right after something is uploaded submit it) to url_for('upload_file') which was '/home/HassanSherien/mysite/Shape_Image' in my case. Then, shouldnt I be able to see these photos in my folder shape_image? I guess the sequence of events is confusing me now @v25 – Cherry Nov 23 '19 at 20:34
  • Thank you!! Now I only get the error message "Method Not Allowed: The method is now allowed for the request URL." Which I searched up means that everything is processing fine but I do not have premission like you said might occur. Since I am doing this through python anywhere and I cannot change the directory premission, I will attempt to contact them and see if there is anyway to bypass this issue. Although, thank you again for all of your help :D @v25 – Cherry Nov 23 '19 at 22:26
  • You probably forgot `method=['POST']` in one of your `@app.route` drecorators. – v25 Nov 23 '19 at 22:49
  • I made sure that all of them had that but the same error persists! I saw in an online thread that changing ``"/login/"`` in my ``@app.route`` section to ``"/"`` should fix the issue which is what I tried as well instead of getting that 405 error it just refreshes the homepage of my app @v25 – Cherry Nov 24 '19 at 00:32
  • careful of which route you pass `methods=['POST']` to. If that route has to be hit in the browser and render a template with a form, you'll get 'method not allowed'. This is fine if said route only handles the upload. If you're doing some logic in there to accept the upload OR render the form, then you porbably want `methods=['POST','GET']` If you don't specify `methods` at-all, it defaults to GET. This is fine if it's a route which only renders the form. You could build this with a single route to handle both, or two routes each of which handles one request method if you see what I mean. – v25 Nov 24 '19 at 02:03
  • I somewhat understand what you are saying. So since my route is not just handling upload which I would only need ``methods=['POST']`` for, but it is also accepting the upload and then using it in later python code I would need ``methods=['POST','GET']``. Although, with what was done above, it should still be able to save the photos in the folder because it was given the instructions to get those photos and place them in the upload_folder. Should I continue this conversation in personal message section? I am unsure if my comments are helpful to others or just me not understanding fully. @v25 – Cherry Nov 24 '19 at 23:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/202995/discussion-between-v25-and-cherry). – v25 Nov 24 '19 at 23:37