首页 > 解决方案 > 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?

标签: pythonflask

解决方案


首先,file.html模板中文件的链接可能应该在循环之外for——否则,链接会出现多次,这可能不是你想要的。

其次,根据您的/downloads路线,您url_for对下载链接的调用不匹配。它应该是:

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

您需要提供filename作为参数,以便烧瓶服务器可以将其与路由 & in 匹配url_for,您需要提供函数的名称- 在这种情况下是download而不是downloads.

最后,您的/browser路由将子目录添加到文件名之前 - 因此当您传递currentFile给 HTML 模板时,它将包含目录前缀 - 您将要删除它,否则您的链接将无法正常工作。然后文件下载将起作用,因为在您的/downloads路线中,filename无论如何您都要在目录前面加上前缀。因此,当您渲染 HTML 模板时,使用os.path.basename()获取没有目录的文件名,即

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

推荐阅读