Как правильно думать о пути к файлам в приложении Flask, обслуживаемом на Apache с помощью mod_wsgi - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь разрешить пользователям загружать csv-файлы из моего приложения фляги, но по маршруту, который обрабатывает загрузку файлов с сервера ubuntu 18, на котором работает Apache2.

import flask
import os
from io import BytesIO

basedir = os.path.abspath(os.path.dirname(__file__))

app = flask.Flask(__name__)
app.config["DEBUG"] = True

@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report,action):
    if action == 'download': 
        files = os.listdir(os.path.join(basedir, f'static/reports/{report}'))
        filepath = url_for(f'static/reports/{report}/{files[-1]}')
        output = BytesIO()
        with open(filepath, 'rb') as f:
            data = f.read()
        output.write(data)
        output.seek(0)
        return send_file(output,attachment_filename=files[-1], as_attachment=True)

Но я получаю эту ошибку: [Errno 2] No such file or directory: '/static/reports'

Моя конфигурация Apache2 уже имеет псевдоним для статических файлов вот так:

Alias /static /var/www/FlaskApp/FlaskApp/static
<Directory /var/www/FlaskApp/FlaskApp/static/>
   Order allow,deny
   Allow from all
</Directory>

Я также пытался создать псевдоним для своей папки отчетов в static, но я все еще получаю те же результаты.

Есть что-то очевидное, что я упускаю?

1 Ответ

0 голосов
/ 08 января 2019

Ваша ошибка использует url_for() для генерации пути. url_for() генерирует URL пути, а не пути к файловым системам. Вы не можете использовать результат, чтобы открыть локальный файл. url_for() используется для отправки браузера в правильное местоположение.

Вы обслуживаете файлы по стандартному пути static. Просто оставьте выяснение, где находится Flask, объект app / current_app имеет атрибут .static_folder .

Вы также хотите использовать функцию send_from_directory() для непосредственного обслуживания файлов. Здесь нет необходимости сначала загружать данные в объект BytesIO(). send_from_directory принимает относительный путь в качестве второго аргумента.

Это должно работать:

@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report, action):
    if action == 'download': 
        files = os.listdir(os.path.join(app.static_folder, 'reports', report))
        filename = files[-1]
        filepath = os.path.join('reports', report, filename)
        return send_from_directory(app.static_folder, filepath, as_attachment=True)

Я пропустил attachment_filename, потому что по умолчанию уже используется имя файла обслуживаемого файла.

Возможно, вам придется переосмыслить стратегию files[-1]. os.listdir() создает файлы в произвольном порядке (в любом порядке ОС выбирает наиболее удобный). Если вы ожидаете, что это будет последний созданный или измененный файл, сначала вам придется выполнить собственную сортировку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...