Поиск по сайту:

Как обрабатывать данные входящего запроса в Flask


Введение

Веб-приложениям часто требуется обработка входящих данных запросов от пользователей. Эта полезная нагрузка может быть в форме строк запроса, данных формы и объектов JSON. Flask, как и любой другой веб-фреймворк, позволяет получить доступ к данным запроса.

В этом руководстве вы создадите приложение Flask с тремя маршрутами, которые принимают строки запроса, данные формы или объекты JSON.

Предпосылки

Для выполнения этого урока вам понадобятся:

  • Для этого проекта потребуется установить Python в локальной среде.
  • В этом проекте virtualenv будет использоваться в одной команде.
  • Для тестирования конечных точек API потребуется загрузить и установить такой инструмент, как Postman.

Это руководство было проверено с помощью Pipenv v2020.11.15, Python v3.9.0 и Flask v1.1.2.

Настройка проекта

Чтобы продемонстрировать различные способы использования запросов, вам потребуется создать приложение Flask. Несмотря на то, что в примере приложения используется упрощенная структура для функций представления и маршрутов, то, что вы узнаете в этом руководстве, может быть применено к любому методу организации ваших представлений, например представлениям на основе классов, схемам или расширениям, таким как Flask-Via.

Во-первых, вам нужно создать каталог проекта. Откройте терминал и выполните следующую команду:

  1. mkdir flask_request_example

Затем перейдите в новый каталог:

  1. cd flask_request_example

Затем установите Flask. Откройте терминал и выполните следующую команду:

  1. pipenv install Flask

Команда pipenv создаст виртуальную среду для этого проекта, Pipfile, установит flask и Pipfile.lock.

Чтобы активировать виртуальную среду проекта, выполните следующую команду:

  1. pipenv shell

Чтобы получить доступ к входящим данным в Flask, вы должны использовать объект request. Объект request содержит все входящие данные из запроса, включая среди прочего тип mimetype, реферер, IP-адрес, необработанные данные, метод HTTP и заголовки.

Хотя вся информация, содержащаяся в объекте request, может быть полезна, для целей этой статьи вы сосредоточитесь на данных, которые обычно напрямую предоставляются вызывающей стороной конечной точки.

Чтобы получить доступ к объекту запроса во Flask, вам нужно будет импортировать его из библиотеки Flask:

from flask import request

Затем у вас есть возможность использовать его в любой из ваших функций просмотра.

Используйте редактор кода для создания файла app.py. Импортируйте Flask и объект request. А также установите маршруты для query-example, form-example и json-example:

# import main Flask class and request object
from flask import Flask, request

# create the Flask app
app = Flask(__name__)

@app.route('/query-example')
def query_example():
    return 'Query String Example'

@app.route('/form-example')
def form_example():
    return 'Form Data Example'

@app.route('/json-example')
def json_example():
    return 'JSON Object Example'

if __name__ == '__main__':
    # run app in debug mode on port 5000
    app.run(debug=True, port=5000)

Затем откройте терминал и запустите приложение с помощью следующей команды:

  1. python app.py

Приложение запустится на порту 5000, поэтому вы можете просмотреть каждый маршрут в своем браузере по следующим ссылкам:

http://127.0.0.1:5000/query-example (or localhost:5000/query-example)
http://127.0.0.1:5000/form-example (or localhost:5000/form-example)
http://127.0.0.1:5000/json-example (or localhost:5000/json-example)

Код устанавливает три маршрута, и при посещении каждого маршрута будут отображаться сообщения Пример строки запроса, Пример данных формы и Пример объекта JSON соответственно.

Использование аргументов запроса

Аргументы URL-адреса, которые вы добавляете в строку запроса, — это распространенный способ передачи данных в веб-приложение. Просматривая веб-страницы, вы, вероятно, уже сталкивались со строкой запроса.

Строка запроса выглядит следующим образом:

example.com?arg1=value1&arg2=value2

Строка запроса начинается после знака вопроса (?):

example.com?arg1=value1&arg2=value2

И имеет пары ключ-значение, разделенные символом амперсанда (&):

example.com?arg1=value1&arg2=value2

Для каждой пары за ключом следует знак равенства (=), а затем значение.

arg1 : value1
arg2 : value2

Строки запроса полезны для передачи данных, не требующих действий пользователя. Вы можете сгенерировать строку запроса где-нибудь в своем приложении и добавить ее к URL-адресу, чтобы, когда пользователь делает запрос, данные автоматически передавались ему. Строка запроса также может быть сгенерирована формами, у которых в качестве метода используется GET.

Давайте добавим строку запроса к маршруту query-example. В этом гипотетическом примере вы укажете имя языка программирования, которое будет отображаться на экране. Создайте ключ language и значение Python:

http://127.0.0.1:5000/query-example?language=Python

Если вы запустите приложение и перейдете по этому URL-адресу, вы увидите, что оно по-прежнему отображает сообщение Пример строки запроса.

Вам нужно будет запрограммировать часть, которая обрабатывает аргументы запроса. Этот код будет читать ключ language с помощью request.args.get(language) или request.args[language].

При вызове request.args.get(language) приложение будет продолжать работать, если ключ language не существует в URL-адресе. В этом случае результатом метода будет None.

При вызове request.args[language] приложение вернет ошибку 400, если ключ language не существует в URL-адресе.

При работе со строками запроса рекомендуется использовать request.args.get(), чтобы предотвратить сбой приложения.

Давайте прочитаем ключ language и отобразим его в качестве вывода.

Измените маршрут query-example в app.py, указав следующий код:

@app.route('/query-example')
def query_example():
    # if key doesn't exist, returns None
    language = request.args.get('language')

    return '''<h1>The language value is: {}</h1>'''.format(language)

Затем запустите приложение и перейдите по URL-адресу:

http://127.0.0.1:5000/query-example?language=Python

Браузер должен отобразить следующее сообщение:

Output
The language value is: Python

Аргумент из URL присваивается переменной language, а затем возвращается в браузер.

Чтобы добавить дополнительные параметры строки запроса, вы можете добавить амперсанд и новые пары ключ-значение в конец URL-адреса. Создайте ключ framework и значение Flask:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask

И если вы хотите больше, продолжайте добавлять амперсанд и пары ключ-значение. Создайте ключ website и значение DigitalOcean:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean

Чтобы получить доступ к этим значениям, вы по-прежнему будете использовать либо request.args.get(), либо request.args[]. Давайте используем оба, чтобы продемонстрировать, что происходит, когда отсутствует ключ. Измените маршрут query_example, чтобы присвоить значение результатов переменным, а затем отобразить их:

@app.route('/query-example')
def query_example():
    # if key doesn't exist, returns None
    language = request.args.get('language')

    # if key doesn't exist, returns a 400, bad request error
    framework = request.args['framework']

    # if key doesn't exist, returns None
    website = request.args.get('website')

    return '''
              <h1>The language value is: {}</h1>
              <h1>The framework value is: {}</h1>
              <h1>The website value is: {}'''.format(language, framework, website)

Затем запустите приложение и перейдите по URL-адресу:

http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean

Браузер должен отобразить следующее сообщение:

Output
The language value is: Python The framework value is: Flask The website value is: DigitalOcean

Удалите ключ language из URL:

http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean

Браузер должен отображать следующее сообщение с None, когда значение для language не указано:

Output
The language value is: None The framework value is: Flask The website value is: DigitalOcean

Удалите ключ framework из URL-адреса:

http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean

Браузер должен столкнуться с ошибкой, поскольку он ожидает значение для framework:

Output
werkzeug.exceptions.BadRequestKeyError werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'framework'

Теперь вы понимаете, как обрабатывать строки запросов. Перейдем к следующему типу входящих данных.

Использование данных формы

Данные формы поступают из формы, которая была отправлена как POST-запрос на маршрут. Таким образом, вместо того, чтобы видеть данные в URL-адресе (за исключением случаев, когда форма отправляется с запросом GET), данные формы будут переданы в приложение за кулисами. Несмотря на то, что вы не можете легко увидеть передаваемые данные формы, ваше приложение все равно может их прочитать.

Чтобы продемонстрировать это, измените маршрут form-example в app.py, чтобы он принимал запросы GET и POST и возвращал форму:

# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
    return '''
              <form method="POST">
                  <div><label>Language: <input type="text" name="language"></label></div>
                  <div><label>Framework: <input type="text" name="framework"></label></div>
                  <input type="submit" value="Submit">
              </form>'''

Затем запустите приложение и перейдите по URL-адресу:

http://127.0.0.1:5000/form-example

Браузер должен отображать форму с двумя полями ввода — одно для language и одно для framework — и кнопку отправки.

Самое важное, что нужно знать об этой форме, это то, что она выполняет запрос POST к тому же маршруту, который сгенерировал форму. Все ключи, которые будут считаны в приложении, берутся из атрибутов name в наших входных данных формы. В этом случае language и framework — это имена входных данных, поэтому у вас будет доступ к ним в приложении.

Внутри функции просмотра вам нужно будет проверить, является ли метод запроса GET или POST. Если это запрос GET, вы можете отобразить форму. В противном случае, если это запрос POST, вам нужно будет обработать входящие данные.

Измените маршрут form-example в app.py с помощью следующего кода:

# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
    # handle the POST request
    if request.method == 'POST':
        language = request.form.get('language')
        framework = request.form.get('framework')
        return '''
                  <h1>The language value is: {}</h1>
                  <h1>The framework value is: {}</h1>'''.format(language, framework)

    # otherwise handle the GET request
    return '''
           <form method="POST">
               <div><label>Language: <input type="text" name="language"></label></div>
               <div><label>Framework: <input type="text" name="framework"></label></div>
               <input type="submit" value="Submit">
           </form>'''

Затем запустите приложение и перейдите по URL-адресу:

http://127.0.0.1:5000/form-example

Заполните поле language значением Python и поле framework значением Flask. Затем нажмите Отправить.

Браузер должен отобразить следующее сообщение:

Output
The language value is: Python The framework value is: Flask

Теперь вы понимаете, как обрабатывать данные формы. Перейдем к следующему типу входящих данных.

Использование данных JSON

Данные JSON обычно создаются процессом, который вызывает маршрут.

Пример объекта JSON выглядит следующим образом:

{
    "language" : "Python",
    "framework" : "Flask",
    "website" : "Scotch",
    "version_info" : {
        "python" : "3.9.0",
        "flask" : "1.1.2"
    },
    "examples" : ["query", "form", "json"],
    "boolean_test" : true
}

Эта структура позволяет передавать гораздо более сложные данные, чем строки запроса и данные формы. В примере вы видите вложенные объекты JSON и массив элементов. Flask может обрабатывать этот формат данных.

Измените маршрут form-example в app.py, чтобы он принимал запросы POST и игнорировал другие запросы, такие как GET:

@app.route('/json-example', methods=['POST'])
def json_example():
    return 'JSON Object Example'

В отличие от веб-браузера, используемого для строк запроса и данных формы, в целях этой статьи для отправки объекта JSON вы будете использовать Postman для отправки пользовательских запросов на URL-адреса.

Примечание. Если вам нужна помощь в навигации по интерфейсу Postman для запросов, обратитесь к официальной документации.

В Postman добавьте URL-адрес и измените тип на POST. На вкладке body измените значение на raw и выберите JSON в раскрывающемся списке.

Эти настройки необходимы, чтобы Postman мог правильно отправлять данные JSON, и чтобы ваше приложение Flask понимало, что оно получает JSON:

POST http://127.0.0.1:5000/json-example
Body
raw JSON

Затем скопируйте предыдущий пример JSON в текстовый ввод.

Отправьте запрос, и вы должны получить в качестве ответа Пример объекта JSON. Это довольно антиклиматически, но этого следовало ожидать, потому что код для обработки ответа данных JSON еще не написан.

Чтобы прочитать данные, вы должны понимать, как Flask переводит данные JSON в структуры данных Python:

  • Все, что является объектом, преобразуется в словарь Python. {key : value} в JSON соответствует somedict[key], который возвращает значение в Python.
  • Массив в JSON преобразуется в список в Python. Поскольку синтаксис тот же, вот пример списка: [1,2,3,4,5]
  • Значения внутри кавычек в объекте JSON становятся строками в Python.
  • Булевы значения true и false становятся True и False в Python.
  • Наконец, числа без кавычек в Python становятся числами.

Теперь давайте поработаем над кодом для чтения входящих данных JSON.

Во-первых, давайте назначим все из объекта JSON в переменную, используя request.get_json().

request.get_json() преобразует объект JSON в данные Python. Давайте назначим данные входящего запроса переменным и вернем их, внеся следующие изменения в маршрут json-example:

# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
    request_data = request.get_json()

    language = request_data['language']
    framework = request_data['framework']

    # two keys are needed because of the nested object
    python_version = request_data['version_info']['python']

    # an index is needed because of the array
    example = request_data['examples'][0]

    boolean_test = request_data['boolean_test']

    return '''
           The language value is: {}
           The framework value is: {}
           The Python version is: {}
           The item at index 0 in the example list is: {}
           The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)

Обратите внимание, как вы получаете доступ к элементам, которые не находятся на верхнем уровне. [версия][python] используется, потому что вы вводите вложенный объект. И [examples][0] используется для доступа к 0-му индексу в массиве примеров.

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

# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
    request_data = request.get_json()

    language = None
    framework = None
    python_version = None
    example = None
    boolean_test = None

    if request_data:
        if 'language' in request_data:
            language = request_data['language']

        if 'framework' in request_data:
            framework = request_data['framework']

        if 'version_info' in request_data:
            if 'python' in request_data['version_info']:
                python_version = request_data['version_info']['python']

        if 'examples' in request_data:
            if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):
                example = request_data['examples'][0]

        if 'boolean_test' in request_data:
            boolean_test = request_data['boolean_test']

    return '''
           The language value is: {}
           The framework value is: {}
           The Python version is: {}
           The item at index 0 in the example list is: {}
           The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)

Запустите приложение и отправьте пример запроса JSON с помощью Postman. В ответ вы получите следующий вывод:

Output
The language value is: Python The framework value is: Flask The Python version is: 3.9 The item at index 0 in the example list is: query The boolean value is: false

Теперь вы понимаете, как обращаться с объектами JSON.

Заключение

В этой статье вы создали приложение Flask с тремя маршрутами, которые принимают строки запроса, данные формы или объекты JSON.

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

Предупреждение. Одной из тем, не затронутой в этой статье, была очистка пользовательского ввода. Дезинфекция пользовательского ввода гарантирует, что данные, считанные приложением, не приведут к неожиданному сбою или обходу мер безопасности.

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