Загрузка и загрузка файлов с помощью фляжки

Я пытаюсь написать действительно просто webapp с PythonAnywhere и Flask, который позволяет пользователю загружать текстовый файл, генерирует файл csv, а затем позволяет пользователю загружать файл csv. Это не должно быть фантазией, это только должно работать. Я уже написал программу для генерации csv из txt файла на диске.

В настоящий момент моя функция открывает файл на диске с помощью:

with open(INPUTFILE, "r") as fname:

и записывает csv с помощью:

with open(OUTPUTFILE, 'w') as fname:

с INPUTFILE и OUTPUTFILE будут именами строк.

Было бы лучше, если бы я обрабатывал файлы как объекты, возвращаемые флягой /html каким-то образом?

Я не знаю, как это сделать. Как я должен структурировать эту программу? Сколько HTML-шаблонов мне нужно? Я бы предпочел работать с файлами, не сохраняя их нигде, но если мне нужно сохранить их в каталоге PythonAnywhere, я бы мог. Как я могу это сделать?

Ответы

Ответ 1

PythonAnywhere dev здесь. Это хороший вопрос о флеске и веб-разработке в целом, а не в конкретной нашей системе, поэтому я попытаюсь дать общий ответ без каких-либо конкретных для нас целей: -)

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

  • Я предполагаю, что файлы, которые вы загружаете, не огромны и могут поместиться в разумный объем памяти - пусть и меньше мегабайта.
  • Я предполагаю, что программа, которую вы уже написали для создания CSV из текстового файла, находится в Python и что она (или, возможно, более вероятно, может быть легко изменена) иметь функцию, которая принимает строка, содержащая содержимое текстового файла, и возвращает содержимое, которое необходимо записать в CSV.

Если это так, то лучший способ структурировать ваше приложение Flask - это обработать все внутри Flask. Пример кода стоит тысячи слов, поэтому здесь простой, который я собираю, который позволяет пользователю загружать текстовый файл, запускает его через функцию под названием transform (где функция из вашей программы конверсии будет входить в нее - - mine просто заменяет = на , в течение всего файла) и отправляет результаты обратно в браузер. Здесь есть живая версия этого приложения на PythonAnywhere.

from flask import Flask, make_response, request

app = Flask(__name__)

def transform(text_file_contents):
    return text_file_contents.replace("=", ",")


@app.route('/')
def form():
    return """
        <html>
            <body>
                <h1>Transform a file demo</h1>

                <form action="/transform" method="post" enctype="multipart/form-data">
                    <input type="file" name="data_file" />
                    <input type="submit" />
                </form>
            </body>
        </html>
    """

@app.route('/transform', methods=["POST"])
def transform_view():
    file = request.files['data_file']
    if not file:
        return "No file"

    file_contents = file.stream.read().decode("utf-8")

    result = transform(file_contents)

    response = make_response(result)
    response.headers["Content-Disposition"] = "attachment; filename=result.csv"
    return response

Относительно ваших других вопросов:

  • Шаблоны: я не использовал шаблон для этого примера, потому что я хотел, чтобы все это входило в один кусок кода. Если бы я делал это правильно, я бы поместил материал, созданный в представлении form, в шаблон, но все это.
  • Можете ли вы это сделать, записав файлы - да, вы можете, и загруженный файл можно сохранить с помощью метода save( имя_файла ) на объекте file, который я использую stream свойство. Но если ваши файлы довольно малы (согласно моему предположению выше), то, вероятно, имеет смысл обрабатывать их в памяти, как это делает код выше.

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

Ответ 2

Лучше добавить

response.headers["Cache-Control"] = "must-revalidate"
response.headers["Pragma"] = "must-revalidate"
response.headers["Content-type"] = "application/csv"

Если вы не добавляете тип контента, FF 48.0 сообщила об этом как html и открыла диалоговое окно "Сохранить" один раз для HTML, а затем для CSV. Если вы не добавляете Cache-Control, ваш результат может быть кэширован, и если вы обслуживаете активный контент, это не то, что вы хотите. Если вы используете must-revalidate без возраста, он будет эффективно служить в качестве кеша - см. здесь и здесь для объяснения.