Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Flask и загрузка файлов: success story

Anna | 16.06.2014 | нет комментариев
Добродушный вечер, Програюзер. Хочу поделиться небольшим навыком ограничения размера загружаемого файла. Каждый навык получен эмпирическим путем.

Как выглядело ТЗ:

  1. В образце создаем формочку с полем для файлов
  2. На сервере проверяем растяжение файла и его размер
  3. Если все данные удовлетворяются — загружаем файл и сберегаем ссылку в БД

Все выглядит легко, но грусть догнала меня при проверке размера файла. Как я решил эту загвоздку? Добросердечно пожаловать под програкат.

Предисловие

По началу все шло легко отменно — и образец сделал, и серверную часть накодил, и все загружается — любо-дорого глядеть. Но здесь я понимаю, что мне безусловно не нужно, чтообы какой-нибудь добродушный человече начал сливать мне 4 гб. траффика на сервер. Гуглим и находим формальный док, в котором видим магические строчки:

By default Flask will happily accept file uploads to an unlimited amount of memory, but you can limit that by setting the MAX_CONTENT_LENGTH config key:

from flask import Flask, Request

app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

Отменно! Добавляем строчку в конфиг, запускаем, и… И получаем ошибку 413… Беда… Гуглим, находимwerkzeug.exceptions и RequestEnityTooLarge. Пытаемся завести конструкцию вида

try:
    file = request.files["file"]
except RequestEnityTooLarge as e:
    return "ERROR", 200

но без итога — браузер не хочет возвращать что-то помимо ошибки. Даже хваленый

@app.errorhandler(413)

ничем мне не помог, итог в консоль не в счет — заказчику это по-барабану.

Продолжение

Ломал голову я дней 5, пока не добрался до начинкиFileStorage. Данный класс наследуется от object и имеет способ read, тот, что изготавливает чтение содержимого в оперативную память. А у этого способа есть добровольный довод size, тот, что устанавливает наивысший размер считываемой информации. Отсель и танцуем.

Набрасываем черновик:

from flask import Flask, render_template, request

MAX_FILE_SIZE = 1024 * 1024   1

app = Flask(__name__)

@app.route("/", methods=["POST", "GET"])
def index():
    args = {"method": "GET"}
    if request.method == "POST":
        file = request.files["file"]
        if bool(file.filename):
            file_bytes = file.read(MAX_FILE_SIZE)
            args["file_size_error"] = len(file_bytes) == MAX_FILE_SIZE
        args["method"] = "POST"
    return render_template("index.html", args=args)

if __name__ == "__main__":
    app.run(debug=True)

где в переменной MAX_FILE_SIZE указываем наивысший размер файла 1 байт для отлова превышения. Остальное, думаю, объяснять не нужно, если что — воопросы в комментарии.

Набрасываем образец:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Uploads</title>
</head>
<body>
    {% if args["method"] == "POST" %}
        {% if args["file_size_error"] %}
            <h1>Размер файла превышает 1мб.!</h1>
        {% else %}
            <h1>Файл удачно загружен.</h1>
        {% endif %}
    {% endif %}
    <form action="/" method="POST" enctype="multipart/form-data">
        <input type="file" name="file">
        <button type="submit">Загрузить</button>
    </form>
</body>
</html>

Запускаем, проверяем. При выдаче файла размером больше 1мб. на нас будут орать, кричать и материться, а мы можем достаточно потереть руки. Все работает.

Выводы

Что дозволено сказать про выводы? Допустимо, этокостыли. Допустимо, я чайник, ламер и дно. Но даже в maillist’е разработчиков мне не дали типичного решения данной задачи.
Однако, и у данного решения есть минус, а именно варьирование ограничения и число оперативной памяти.

На сей ноте хочу распрощаться. Спасибо за то, что прочли, всю критику буду рад выслушать в комментариях. Каждому везения!

 

 Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB