I’m trying to create a web app with Flask that lets a user upload a file and serve them to another user. Right now, I can upload the file to the upload_folder correctly. But I can’t seem to find a way to let the user download it back.

I’m storing the name of the filename into a database.

I have a view serving the database objects. I can delete them too.

@app.route('/dashboard', methods=['GET', 'POST'])
def dashboard():

    problemes = Probleme.query.all()

    if 'user' not in session:
        return redirect(url_for('login'))

    if request.method == 'POST':
        delete = Probleme.query.filter_by(id=request.form['del_button']).first()
        db.session.delete(delete)
        db.session.commit()
        return redirect(url_for('dashboard'))

    return render_template('dashboard.html', problemes=problemes)

In my HTML I have:

<td><a href="https://stackoverflow.com/questions/24577349/{{ url_for("download', filename=probleme.facture) }}">Facture</a></td>

and a download view :

@app.route('/uploads/<path:filename>', methods=['GET', 'POST'])
def download(filename):
    return send_from_directory(directory=app.config['UPLOAD_FOLDER'], filename=filename)

But it’s returning :

Not Found

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

I just want to link the filename to the object and let the user download it (For every object in the same view)

You need to make sure that the value you pass to the directory argument is an absolute path, corrected for the current location of your application.

The best way to do this is to configure UPLOAD_FOLDER as a relative path (no leading slash), then make it absolute by prepending current_app.root_path:

@app.route('/uploads/<path:filename>', methods=['GET', 'POST'])
def download(filename):
    uploads = os.path.join(current_app.root_path, app.config['UPLOAD_FOLDER'])
    return send_from_directory(directory=uploads, filename=filename)

It is important to reiterate that UPLOAD_FOLDER must be relative for this to work, e.g. not start with a /.

A relative path could work but relies too much on the current working directory being set to the place where your Flask code lives. This may not always be the case.

To download file on flask call. File name is Examples.pdf
When I am hitting 127.0.0.1:5000/download it should get
download.

Example:

from flask import Flask
from flask import send_file
app = Flask(__name__)

@app.route('/download')
def downloadFile ():
    #For windows you need to use drive name [ex: F:/Example.pdf]
    path = "/Examples.pdf"
    return send_file(path, as_attachment=True)

if __name__ == '__main__':
    app.run(port=5000,debug=True) 

I was also developing a similar application. I was also getting not found error even though the file was there. This solve my problem. I mention my download folder in ‘static_folder’:

app = Flask(__name__,static_folder="pdf")

My code for the download is as follows:

@app.route('/pdf/<path:filename>', methods=['GET', 'POST'])
def download(filename):    
    return send_from_directory(directory='pdf', filename=filename)

This is how I am calling my file from html.

<a class="label label-primary" href=http://stackoverflow.com/pdf/{{  post.hashVal }}.pdf target="_blank"  style="margin-right: 5px;">Download pdf </a>
<a class="label label-primary" href=http://stackoverflow.com/pdf/{{  post.hashVal }}.png target="_blank"  style="margin-right: 5px;">Download png </a>

#HTML Code
 
<ul>
 {% for file in files %}
  <li> <a href="{{ url_for('download', filename=file) }}">{{ file }}</a></li>
 {% endfor %}
</ul>


#Python Code

from flask import send_from_directory

app.config['UPLOAD_FOLDER']='logs'


@app.route('/uploads/<path:filename>', methods=['GET', 'POST'])
def download(filename):
    print(app.root_path)
    full_path = os.path.join(app.root_path, app.config['UPLOAD_FOLDER'])
    print(full_path)
    return send_from_directory(full_path, filename)