简体   繁体   中英

flask send_from_directory within a file representation

Hi I currently have a flask app that shows files and their details, now I want flask to also allow file downloads from the page of the represented file

I tried a couple things including send_from_directory() which didn't work. So my question is how can I add a working download link to the page?

@app.route('/browser/<path:urlFilePath>')
def browser(urlFilePath):
    nestedFilePath = os.path.join(FILE_SYSTEM_ROOT, urlFilePath)
    if os.path.isdir(nestedFilePath):
        itemList = os.listdir(nestedFilePath)
        fileProperties = {"filepath": nestedFilePath}
        if not urlFilePath.startswith("/"):
            urlFilePath = "/" + urlFilePath
        return render_template('browse.html', urlFilePath=urlFilePath, itemList=itemList)
    if os.path.isfile(nestedFilePath):
        fileProperties = {"filepath": nestedFilePath}
        sbuf = os.fstat(os.open(nestedFilePath, os.O_RDONLY)) #Opening the file and getting metadata
        fileProperties['type'] = stat.S_IFMT(sbuf.st_mode) 
        fileProperties['mode'] = stat.S_IMODE(sbuf.st_mode) 
        fileProperties['mtime'] = sbuf.st_mtime 
        fileProperties['size'] = sbuf.st_size 
        if not urlFilePath.startswith("/"):
            urlFilePath = "/" + urlFilePath
        return render_template('file.html', currentFile=nestedFilePath, fileProperties=fileProperties)
    return 'something bad happened'

@app.route('/downloads/<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)

And with the following HTML

{% extends 'base.html' %}


{% block header %}
<h1>{% block title %}Filebrowser{% endblock %}</h1>
{% endblock %}
{% block content %}
    <p>Current file: {{ currentFile }}</p>
    <p>
        <table>
            {% for key, value in fileProperties.items() %}
            <tr>
                <td>{{ key }}</td>
                <td>{{ value }}</td>
            </tr>
            <tr>
                <a href="{{ url_for('downloads', ['image_name']) }}">File</a>
            </tr>

            {% endfor %}


        </table>
    </p>
    {% endblock %}

I want the download link on that page to work for the {{ currentFile }} can anyone help me out?

Firstly, the link to the file in your file.html template should probably go outside the for loop -- otherwise, the link will appear multiple times which is probably not what you want.

Secondly, based on your /downloads route, your call to url_for for the download link doesn't match up. It should be:

<a href="{{ url_for('download', filename=currentFile) }}">File</a>

You need to supply the filename as an argument so that the flask server can match it to the route & in url_for , you need to supply the name of the function - which in this case is download instead of downloads .

Lastly, your /browser route prepends the subdirectory to the filename - so when you pass currentFile to the HTML template, it will contain the directory prefix -- which you will want to strip, otherwise your link wouldn't work. The file download would then work since in your /downloads route, you prefix the filename with the directory anyway. Hence, when you render the HTML template, use os.path.basename() to obtain the filename without the directory, ie

return render_template('file.html', currentFile=os.path.basename(nestedFilePath), fileProperties=fileProperties)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM