Быстрый старт¶
Рвётесь в бой? Эта страница даёт хорошее введение в Flask. Предполагается, что вы уже имеете установленный Flask. Если это не так, обратитесь к секции Инсталляция .
Минимальное приложение¶
Минимальное приложение Flask выглядит примерно так:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
Просто сохраните его под именем наподобие hello.py и запустите с помощью вашего интерпретатора Python. Только, пожалуйста, не давайте приложению имя flask.py , так как это вызовет конфликт с самим Flask.
$ python hello.py * Running on http://127.0.0.1:5000/
Проследовав по ссылке http://127.0.0.1:5000/ вы увидите ваше приветствие миру.
Итак, что же делает этот код?
- Сначала мы импортировали класс Flask . Экземпляр этого класса и будет вашим WSGI-приложением.
- Далее мы создаём экземпляр этого класса. Первый аргумент — это имя модуля или пакета приложения. Если вы используете единственный модуль (как в этом примере), вам следует использовать __name__ , потому что в зависимости от того, запущен ли код как приложение, или был импортирован как модуль, это имя будет разным ( ‘__main__’ или актуальное имя импортированного модуля соответственно). Это нужно, чтобы Flask знал, где искать шаблоны, статические файлы и прочее. Для дополнительной информации, смотрите документацию Flask .
- Далее, мы используем декоратор route() , чтобы сказать Flask, какой из URL должен запускать нашу функцию.
- Функция, которой дано имя, используемое также для генерации URL-адресов для этой конкретной функции, возвращает сообщение, которое мы хотим отобразить в браузере пользователя.
- Наконец, для запуска локального сервера с нашим приложением, мы используем функцию run() . Благодаря конструкции if __name__ == ‘__main__’ можно быть уверенным, что сервер запустится только при непосредственном вызове скрипта из интерпретатора Python, а не при его импортировании в качестве модуля.
Для остановки сервера, нажмите Ctrl+C.
Публично доступный сервер
Если вы запустите сервер, вы заметите, что он доступен только с вашего собственного компьютера, а не с какого-либо другого в сети. Так сделано по умолчанию, потому что в режиме отладки пользователь приложения может выполнить код на Python на вашем компьютере.
Если у вас отключена опция debug или вы доверяете пользователям в сети, вы можете сделать сервер публично доступным, просто изменив вызов метода run() таким вот образом:
app.run(host='0.0.0.0')
Это укажет вашей операционной системе, чтобы она слушала сеть со всех публичных IP-адресов.
Режим отладки¶
Метод run() чудесно подходит для запуска локального сервера для разработки, но вы будете должны перезапускать его всякий раз при изменении вашего кода. Это не очень здорово, и Flask здесь может облегчить жизнь. Если вы включаете поддержку отладки, сервер перезагрузит сам себя при изменении кода, кроме того, если что-то пойдёт не так, это обеспечит вас полезным отладчиком.
Существует два способа включить отладку. Или установите флаг в объекте приложения:
app.debug = True app.run()
Или передайте его как параметр при запуске:
app.run(debug=True)
Оба метода вызовут одинаковый эффект.
Несмотря на то, что интерактивный отладчик не работает в многопоточных окружениях (что делает его практически неспособным к использованию на реальных рабочих серверах), тем не менее, он позволяет выполнение произвольного кода. Это делает его главной угрозой безопасности, и поэтому он никогда не должен использоваться на реальных «боевых» серверах.
Снимок экрана с отладчиком в действии:

Предполагаете использовать другой отладчик? Тогда смотрите Работа с отладчиками .
Маршрутизация¶
Современные веб-приложения используют «красивые» URL. Это помогает людям запомнить эти URL, это особенно удобно для приложений, используемых с мобильных устройств с более медленным сетевым соединением. Если пользователь может перейти сразу на желаемую страницу, без предварительного посещения начальной страницы, он с большей вероятностью вернётся на эту страницу и в следующий раз.
Как вы увидели ранее, декоратор route() используется для привязки функции к URL. Вот простейшие примеры:
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello World'
Но это еще не все! Вы можете сделать определенные части URL динамически меняющимися и задействовать в функции несколько правил.
Правила для переменной части¶
Чтобы добавлять к адресу URL переменные части, можно эти особые части выделить как . Затем подобные части передаются в вашу функцию в качестве аргумента — в виде ключевого слова. Также может быть использован конвертер — с помощью задания правила следующего вида . Вот несколько интересных примеров
@app.route('/user/') def show_user_profile(username): # показать профиль данного пользователя return 'User %s' % username @app.route('/post/') def show_post(post_id): # вывести сообщение с данным id, id - целое число return 'Post %d' % post_id
Существуют следующие конвертеры:
| int | принимаются целочисленные значения |
| float | как и int , только значения с плавающей точкой |
| path | подобно поведению по умолчанию, но допускаются слэши |
Уникальные URL / Перенаправления
Правила для URL, работающие в Flask, основаны на модуле маршрутизации Werkzeug. Этот модуль реализован в соответствие с идеей обеспечения красивых и уникальных URL-адресов на основе исторически попавшего в обиход — из поведения Apache и более ранних HTTP серверов.
Возьмём два правила:
@app.route('/projects/') def projects(): return 'The project page' @app.route('/about') def about(): return 'The about page'
Хоть они и выглядят довольно похожими, есть разница в использовании слэша в определении URL. В первом случае, канонический URL имеет завершающую часть projects со слэшем в конце. В этом смысле он похож на папку в файловой системе. В данном случае, при доступе к URL без слэша, Flask перенаправит к каноническому URL с завершающим слэшем.
Однако, во втором случае, URL определен без косой черты — как путь к файлу на UNIX-подобных системах. Доступ к URL с завершающей косой чертой будет приводить к появлению ошибки 404 «Not Found».
Такое поведение позволяет продолжить работать с относительными URL, даже если в конце строки URL пропущен слэш — в соответствии с тем, как работают Apache и другие сервера. Кроме того, URL-адреса останутся уникальными, что поможет поисковым системам избежать повторной переиндексации страницы.
Построение (генерация) URL¶
Раз Flask может искать соответствия в URL, может ли он их генерировать? Конечно, да. Для построения URL для специфической функции, вы можете использовать функцию url_for() . В качестве первого аргумента она принимает имя функции, кроме того она принимает ряд именованных аргументов, каждый из которых соответствует переменной части правила для URL. Неизвестные переменные части добавляются к URL в качестве параметров запроса. Вот некоторые примеры:
>>> from flask import Flask, url_for >>> app = Flask(__name__) >>> @app.route('/') . def index(): pass . >>> @app.route('/login') . def login(): pass . >>> @app.route('/user/') . def profile(username): pass . >>> with app.test_request_context(): . print url_for('index') . print url_for('login') . print url_for('login', next='/') . print url_for('profile', username='John Doe') . / /login /login?next=/ /user/John%20Doe
(Здесь также использован метод test_request_context() , который будет объяснён ниже. Он просит Flask вести себя так, как будто он обрабатывает запрос, даже если мы взаимодействуем с ним через оболочку Python. Взгляните на нижеследующее объяснение. Локальные объекты контекста (context locals) .
Зачем Вам может потребоваться формировать URL-ы с помощью функции их обращения url_for() вместо того, чтобы жёстко задать их в ваших шаблонах? Для этого есть три веские причины:
1. По сравнению с жёстким заданием URL внутри кода обратный порядок часто является более наглядным. Более того, он позволяет менять URL за один шаг, и забыть про необходимость изменять URL повсюду. 2. Построение URL будет прозрачно для вас осуществлять экранирование специальных символов и данных Unicode, так что вам не придётся отдельно иметь с ними дела. 3. Если ваше приложение размещено не в корневой папке URL root (а, скажем, в /myapplication вместо / ), данную ситуацию нужным для вас образом обработает функция url_for() .
Методы HTTP¶
HTTP (протокол, на котором общаются веб-приложения) может использовать различные методы для доступа к URL-адресам. По умолчанию, route отвечает лишь на запросы типа GET , но это можно изменить, снабдив декоратор route() аргументом methods . Вот некоторые примеры:
from flask import request @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': do_the_login() else: show_the_login_form()
Если присутствует метод GET , то автоматически будет добавлен и HEAD . Вам не придётся иметь с ним дело. Также, при этом можно быть уверенным, что запросы HEAD будут обработаны в соответствии с требованиями HTTP RFC (документ с описанием протокола HTTP), так что вам не требуется ничего знать об этой части спецификации HTTP. Кроме того, начиная с Flask версии 0.6, для вас будет автоматически реализован метод OPTIONS автоматически.
Не имеете понятия, что такое метод HTTP? Не беспокойтесь, здесь приводится быстрое введение в методы HTTP, и почему они важны:
HTTP-метод (также часто называемый командой) сообщает серверу, что хочет сделать клиент с запрашиваемой страницей. Очень распространены Следующие методы:
GET Браузер говорит серверу, чтобы он просто получил информацию, хранимую на этой странице, и отослал её. Возможно, это самый распространённый метод. HEAD Браузер просит сервер получить информацию, но его интересует только заголовки, а не содержимое страницы. Приложение предполагает обработать их так же, как если бы был получен запрос GET , но без доставки фактического содержимого. В Flask, вам вовсе не требуется иметь дело с этим методом, так как нижележащая библиотека Werkzeug сделает всё за вас. POST Браузер говорит серверу, что он хочет сообщить этому URL некоторую новую информацию, и что сервер должен убедиться, что данные сохранены и сохранены в единожды. Обычно, аналогичным образом происходит передача из HTML форм на сервер данных. PUT Похоже на POST , только сервер может вызвать процедуру сохранения несколько раз, перезаписывая старые значения более одного раза. Здесь вы можете спросить, зачем это нужно, и есть несколько веских причин, чтобы делать это подобным образом. Предположим, во время передачи произошла потеря соединения: в этой ситуации система между браузером и сервером, ничего не нарушая, может совершенно спокойно получить запрос во второй раз. С POST такое было бы невозможно, потому что он может быть вызван только один раз. DELETE Удалить информацию, расположенную в указанном месте. OPTIONS Обеспечивает быстрый способ выяснения клиентом поддерживаемых для данного URL методов. Начиная с Flask 0.6, это работает для вас автоматически.
Теперь самое интересное: в HTML 4 и XHTML1, единственными методами, которыми форма может отправить серверу данные, являются GET и POST . Но для JavaScript и будущих стандартов HTML вы также можете использовать и другие методы. Кроме того, в последнее время HTTP стал довольно популярным, и теперь браузеры уже не единственные клиенты, использующие HTTP. Например, его используют многие системы контроля версий.
Статические файлы¶
Динамические веб-приложения также нуждаются и в статических файлах. Обычно, именно из них берутся файлы CSS и JavaScript. В идеале ваш веб-сервер уже сконфигурирован так, чтобы обслуживать их для вас, однако в ходе разработке это также может делать и сам Flask. Просто создайте внутри вашего пакета или модуля папку с названием static , и она будет доступна из приложения как /static .
Чтобы сформировать для статических файлов URL, используйте специальное окончание ‘static’ :
url_for('static', filename='style.css')
Этот файл должен храниться в файловой системе как static/style.css .
Визуализация шаблонов¶
Генерация HTML из Python — невесёлое и на самом деле довольно сложное занятие, так как вам необходимо самостоятельно заботиться о безопасности приложения, производя для HTML обработку специальных последовательностей (escaping). Поэтому внутри Flask уже автоматически преднастроен шаблонизатор Jinja2.
Для визуализации шаблона вы можете использовать метод render_template() . Всё, что вам необходимо — это указать имя шаблона, а также переменные в виде именованных аргументов, которые вы хотите передать движку обработки шаблонов:
from flask import render_template @app.route('/hello/') @app.route('/hello/') def hello(name=None): return render_template('hello.html', name=name)
Flask будет искать шаблоны в папке templates . Поэтому, если ваше приложение выполнено в виде модуля, эта папка будет рядом с модулем, а если в виде пакета, она будет внутри вашего пакета:
Первый случай — модуль:
/application.py /templates /hello.html
Второй случай — пакет:
/application /__init__.py /templates /hello.html
При работе с шаблонами вы можете использовать всю мощь Jinja2. За дополнительной информацией обратитесь к официальной Документации по шаблонам Jinja2
Вот пример шаблона:
title>Hello from Flasktitle> if name %> h1>Hello <name >>!h1> else %> h1>Hello World!h1> endif %>
Также, внутри шаблонов вы имеете доступ к объектам request , session и g [1], а также к функции get_flashed_messages() .
Шаблоны особенно полезны при использовании наследования. Если вам интересно, как это работает, обратитесь к документации по заготовкам Template Inheritance . Проще говоря, наследование шаблонов позволяет разместить определённые элементы (такие, как заголовки, элементы навигации и «подвал» страницы) на каждой странице.
Автоматическая обработка специальных (escape-) последовательностей (escaping) включена по умолчанию, поэтому если name содержит HTML, он будет экранирован автоматически. Если вы можете доверять переменной и знаете, что в ней будет безопасный HTML (например, потому что он пришёл из модуля конвертирования разметки wiki в HTML), вы можете пометить её в шаблоне, как безопасную — с использованием класса Markup или фильтра |safe . За дополнительными примерами обратитесь к документации по Jinja2.
Вот основные возможности по работе с классом Markup :
>>> from flask import Markup >>> Markup('Hello %s!') % '' Markup(u'Hello <blink>hacker</blink>!') >>> Markup.escape('') Markup(u'<blink>hacker</blink>') >>> Markup('Marked up » HTML').striptags() u'Marked up \xbb HTML'
Изменено в версии 0.5: Автоматическая обработка escape-последовательностей больше не активирована для всех шаблонов. Вот расширения шаблонов, которые активизируют автообработку: .html , .htm , .xml , .xhtml . Шаблоны, загруженные из строк, не будут обрабатывать специальные последовательности.
| [1] | Затрудняетесь понять, что это за объект — g ? Это то, в чём вы можете хранить информацию для ваших собственных нужд, для дополнительной информации смотрите документацию на этот объект ( g ) и sqlite3 . |
Доступ к данным запроса¶
Для веб-приложений важно, чтобы они реагировали на данные, которые клиент отправляет серверу. В Flask эта информация предоставляется глобальным объектом request . Если у вас есть некоторый опыт по работе с Python, вас может удивить, как этот объект может быть глобальным, и как Flask при этом умудрился остаться ориентированным на многопоточное выполнение.
Локальные объекты контекста (context locals)¶
Информация от инсайдера
Прочтите этот раздел, если вы хотите понять, как это работает, и как вы можете реализовать тесты с локальными переменными контекста. Если вам это неважно, просто пропустите его.
Некоторые объекты в Flask являются глобальными, но необычного типа. Эти объекты фактически являются прокси (посредниками) к объектам, локальным для конкретного контекста. Труднопроизносимо. Но на самом деле довольно легко понять.
Представьте себе контекст, обрабатывающий поток. Приходит запрос, и веб-сервер решает породить новый поток (или нечто иное — базовый объект может иметь дело с системой параллельного выполнения не на базе потоков). Когда Flask начинает осуществлять свою внутреннюю обработку запроса, он выясняет, что текущий поток является активным контекстом и связывает текущее приложение и окружение WSGI с этим контекстом (потоком). Он делает это с умом — так, что одно приложение может, не ломаясь, вызывать другое приложение.
Итак, что это означает для вас? В принципе, вы можете полностью игнорировать, что это так, если вы не делаете чего-либо вроде тестирования модулей. Вы заметите, что код, зависящий от объекта запроса, неожиданно будет работать неправильно, так как отсутствует объект запроса. Решением является самостоятельное создание объекта запроса и его привязка к контексту. Простейшим решением для тестирования модулей является использование менеджера контекстов test_request_context() . В сочетании с оператором with этот менеджер свяжет тестовый запрос так, что вы сможете с ним взаимодействовать. Вот пример:
from flask import request with app.test_request_context('/hello', method='POST'): # теперь, и до конца блока with, вы можете что-либо делать # с контекстом, например, вызывать простые assert-ы: assert request.path == '/hello' assert request.method == 'POST'
Другая возможность — это передача целого окружения WSGI методу request_context() method:
from flask import request with app.request_context(environ): assert request.method == 'POST'
Объект запроса¶
Объект запроса документирован в секции API, мы не будем рассматривать его здесь подробно (смотри request ). Вот широкий взгляд на некоторые наиболее распространённые операции. Прежде всего, вам необходимо импортировать его из модуля flask :
from flask import request
В настоящее время метод запроса доступен через использование атрибута method . Для доступа к данным формы (данным, которые передаются в запросах типа POST или PUT ), вы можете использовать атрибут form . Вот полноценный пример работы с двумя упомянутыми выше атрибутами:
@app.route('/login', methods=['POST', 'GET']) def login(): error = None if request.method == 'POST': if valid_login(request.form['username'], request.form['password']): return log_the_user_in(request.form['username']) else: error = 'Invalid username/password' # следущий код выполняется при методе запроса GET # или при признании полномочий недействительными return render_template('login.html', error=error)
Что произойдёт, если ключ, указанный в атрибуте form , не существует? В этом случае будет возбуждена специальная ошибка KeyError . Вы можете перехватить её подобно стандартной KeyError , но если вы этого не сделаете, вместо этого будет показана страница с ошибкой HTTP 400 Bad Request . Так что во многих ситуациях вам не придётся иметь дело с этой проблемой.
Для доступа к параметрам, представленным в URL ( ?ключ=значение ), вы можете использовать атрибут args :
searchword = request.args.get('key', '')
Мы рекомендуем доступ к параметрам внутри URL через get или через перехват KeyError , так как пользователь может изменить URL, а предъявление ему страницы с ошибкой 400 bad request не является дружественным.
За полным списком методов и атрибутов объекта запроса, обратитесь к следующей документации: request .
Загрузка файлов на сервер¶
В Flask обработка загружаемых на сервер файлов является несложным занятием. Просто убедитесь, что вы в вашей HTML-форме не забыли установить атрибут enctype=»multipart/form-data» , в противном случае браузер вообще не передаст файл.
Загруженные на сервер файлы сохраняются в памяти или во временной папке внутри файловой системы. Вы можете получить к ним доступ, через атрибут объекта запроса files . Каждый загруженный файл сохраняется в этом словаре. Он ведёт себя так же, как стандартный объект Python file , однако он также имеет метод save() , который вам позволяет сохранить данный файл внутрь файловой системы сервера. Вот простой пример, показывающий, как это работает:
from flask import request @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': f = request.files['the_file'] f.save('/var/www/uploads/uploaded_file.txt') .
Если вы хотите до загрузки файла в приложение узнать, как он назван на стороне клиента, вы можете просмотреть атрибут filename . Однако, имейте в виду, что данному значению никогда не стоит доверять, потому что оно может быть подделано. Если вы хотите использовать имя файла на клиентской стороне для сохранения файла на сервере, пропустите его через функцию secure_filename() , которой вас снабдил Werkzeug:
from flask import request from werkzeug import secure_filename @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': f = request.files['the_file'] f.save('/var/www/uploads/' + secure_filename(f.filename)) .
Некоторые более удачные примеры можно найти в разделе заготовок: Загрузка файлов .
Cookies¶
Для доступа к cookies можно использовать атрибут cookies . Для установки cookies можно использовать метод объектов ответа set_cookie . Атрибут объектов запроса cookies — это словарь со всеми cookies, которые передаёт клиент. Если вы хотите использовать сессии, то не используйте cookies напрямую, вместо этого используйте во Flask Сессии , который при работе с cookies даст вам некоторую дополнительную безопасность.
from flask import request @app.route('/') def index(): username = request.cookies.get('username') # Чтобы не получить в случае отсутствия cookie ошибку KeyError # используйте cookies.get(key) вместо cookies[key]
from flask import make_response @app.route('/') def index(): resp = make_response(render_template(. )) resp.set_cookie('username', 'the username') return resp
Заметьте, что cookies устанавливаются в объектах ответа. Так как вы обычно просто возвращаете строки из функций представления, Flask конвертирует их для вас в объекты ответа. Если вы это хотите сделать явно, то можете использовать функцию, make_response() , затем изменив её.
Иногда вы можете захотеть установить cookie в точке, где объект ответа ещё не существует. Это можно сделать, используя заготовку deferred-callbacks .
Также об этом можно почитать здесь: Об ответах .
Ошибки и перенаправления¶
Чтобы перенаправить пользователя в иную конечную точку, используйте функцию redirect() ; для того, чтобы преждевременно прервать запрос с кодом ошибки, используйте функцию abort() function:
from flask import abort, redirect, url_for @app.route('/') def index(): return redirect(url_for('login')) @app.route('/login') def login(): abort(401) this_is_never_executed()
Это довольно бессмысленный пример, потому что пользователь будет перенаправлен с индексной страницы на страницу, на которую у него нет доступа ( 401 означает отказ в доступе), однако он показывает, как это работает.
По умолчанию, для каждого кода ошибки отображается чёрно-белая страница с ошибкой. Если вы хотите видоизменить страницу с ошибкой, то можете использовать декоратор errorhandler() :
from flask import render_template @app.errorhandler(404) def page_not_found(error): return render_template('page_not_found.html'), 404
Обратите внимание на 404 после вызова render_template() . Это сообщит Flask, что код статуса для этой страницы должен быть 404, что означает «не найдено». По умолчанию предполагается код «200», который означает «всё прошло хорошо».
Об ответах¶
Возвращаемое из функции представления значение автоматически для вас конвертируется вас в объект ответа. Если возвращаемое значение является строкой, оно конвертируется в объект ответа в строку в виде тела ответа, код статуса 200 OK и в mimetype со значением text/html . Логика, которую применяет Flask для конвертации возвращаемых значений в объекты ответа следующая:
- Если возвращается объект ответа корректного типа, он прямо возвращается из представления.
- Если это строка, создаётся объект ответа с этими же данными и параметрами по умолчанию.
- Если возвращается кортеж, его элементы могут предоставлять дополнительную информацию. Такие кортежи должны соответствовать форме (ответ, статус, заголовки) , кортеж должен содержать хотя бы один из перечисленных элементов. Значение статус заменит код статуса, а элемент заголовки может быть или списком или словарём с дополнительными значениями заголовка.
- Если ничего из перечисленного не совпало, Flask предполагает, что возвращаемое значение — это допустимая WSGI-заявка, и конвертирует его в объект ответа.
Если вы хотите в результате ответа заполучить объект внутри представления, то можете использовать функцию make_response() .
Представим, что вы имеете подобное представление:
@app.errorhandler(404) def not_found(error): return render_template('error.html'), 404
Вам надо всего лишь обернуть возвращаемое выражение функцией make_response() и получить объект ответа для его модификации, а затем вернуть его:
@app.errorhandler(404) def not_found(error): resp = make_response(render_template('error.html'), 404) resp.headers['X-Something'] = 'A value' return resp
Сессии¶
В дополнение к объекту ответа есть ещё один объект, называемый session , который позволяет вам сохранять от одного запроса к другому информацию, специфичную для пользователя. Это реализовано для вас поверх cookies, при этом используется криптографическая подпись этих cookie. Это означает, что пользователь может посмотреть на содержимое cookie, но не может ничего в ней изменить, если он конечно не знает значение секретного ключа, использованного для создания подписи.
В случае использования сессий вам необходимо установить значение этого секретного ключа. Вот как работают сессии:
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) @app.route('/') def index(): if 'username' in session: return 'Logged in as %s' % escape(session['username']) return 'You are not logged in' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': session['username'] = request.form['username'] return redirect(url_for('index')) return '''''' @app.route('/logout') def logout(): # удалить из сессии имя пользователя, если оно там есть session.pop('username', None) return redirect(url_for('index')) # set the secret key. keep this really secret: app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
Упомянутая escape() осуществляет для вас обработку специальных последовательностей (escaping), что необходимо, если вы не используете движок шаблонов (как в этом примере).
Как генерировать хорошие секретные ключи
Проблемой случайных значений является то, что трудно сказать, что действительно является является случайным. А секретный ключ должен быть настолько случайным, насколько это возможно. У вашей операционной системы есть способы для генерации достаточно случайных значений на базе криптографического случайного генератора, который может быть использован для получения таких ключей:
>>> import os >>> os.urandom(24) '\xfd
Просто возьмите, скопируйте/вставьте это в ваш код, вот и готово.
Замечание о сессиях на базе cookie: Flask возьмёт значения, которые вы помещаете в объект сессии, и сериализует их в cookie. Если вы обнаружили какие-либо значения, которые не сохраняются между запросами, а cookies реально включены, а никаких ясных сообщений об ошибках не было, проверьте размер cookie в ответах вашей страницы и сравните с размером, поддерживаемым веб-браузером.
Message Flashing¶
Хорошие приложения и интерфейсы пользователя дают обратную связь. Если пользователь не получает достаточной обратной связи, вскоре он может начать ненавидеть приложение. При помощи системы всплывающих сообщений Flask предоставляет пользователю по-настоящему простой способ обратной связи. Система всплывающих сообщений обычно делает возможным записать сообщение в конце запроса и получить к нему доступ во время обработки следующего и только следующего запроса. Обычно эти сообщения используются в шаблонах макетов страниц, которые его и отображают.
Чтобы вызвать всплывающие сообщения, используйте метод flash() , чтобы заполучить сообщения, можно использовать метод, также доступный для шаблонов — get_flashed_messages() . Полный пример приведён в разделе Всплывающие сообщения .
Ведение журналов¶
Добавлено в версии 0.3.
Иногда может возникнуть ситуация, в которой вы имеете дело с данными, которые должны быть корректными, но в действительности это не так. К примеру, у вас может быть некий код клиентской стороны, который посылает HTTP-запрос к серверу, однако он очевидным образом неверен. Это может произойти из-за манипуляции пользователя с данными, или из-за неудачной работы клиентского кода. В большинстве случаев ответом, адекватным ситуации будет 400 Bad Request , но иногда, когда надо, чтобы код продолжал работать, это не годится.
Вы по-прежнему хотите иметь журнал того, что пошло не так. Вот где могут пригодиться объекты создания журнала logger . Начиная с Flask 0.3, инструмент для журналирования уже настроен для использования.
Вот некоторые примеры вызовов функции журналирования:
app.logger.debug('Значение для отладки') app.logger.warning('Предупреждение: (%d яблок)', 42) app.logger.error('Ошибка')
Прилагаемый logger это стандартный класс журналирования Logger , так что за подробностями вы можете обратиться к официальной документации по журналированию.
Как зацепиться (hooking) к промежуточному слою WSGI¶
Если вы хотите добавить в ваше приложение слой промежуточного, или связующего для WSGI программного обеспечения (middleware), вы можете обернуть внутреннее WSGI-приложение. К примеру, если вы хотите использовать одно из middleware из пакета Werkzeug для обхода известных багов в lighttpd, вы можете сделать это подобным образом:
from werkzeug.contrib.fixers import LighttpdCGIRootFix app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
Развёртывание приложения на веб-сервере¶
Готовы к развёртыванию на сервере вашего нового приложения Flask? В завершение краткого руководства, вы можете немедленно развернуть приложение на одной из платформ хостинга, предоставляющих бесплатное размещение для малых проектов:
- Развёртывание приложения Flask на Heroku
- Развёртывание WSGI в dotCloud с специфическими для Flask замечаниями
Другие места, где можно разместить ваше приложение:
- Развёртывание приложения Flask на Webfaction
- Развёртывание приложения Flask в Google App Engine
- Общий доступ к локальному хосту с помощью Localtunnel
Если вы управляете собственными хостами и желаете разместиться у себя, смотрите раздел Варианты развёртывания .
Что такое Flask и как на нем быстро написать простой сайт

Рассказываем про один из самых популярных и лаконичных микрофреймворков для Python — Flask. Как написать простое приложение, подключить к нему Bootstrap и базу данных, и есть ли вообще у Flask минусы.
Flask — это микрофреймворк для создания веб-приложений на Python. В нем из коробки доступен только минимальный инструментарий, но при этом он поддерживает расширения так, как будто они реализованы в самом Flask. Расширения для микрофреймворка позволяют коммуницировать с базами данных, проверять формы, контролировать загрузку на сервер, работать с аутентификацией и многое другое.
Первая публичная версия Flask вышла 16 апреля 2010 года. Автор проекта — Армин Ронахер , который возглавлял команду энтузиастов в Python-разработке Poocco. Flask основан на быстром и расширяемом механизме шаблонов Jinja и наборе инструментов Werkzeug. Кроме того, Flask использует одну из самых передовых служебных библиотек WSGI (Web Server Gateway Interface — стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, и самим веб-сервером).
При этом WSGI тоже разработал Армин Ронахер. По его словам, идея Flask изначально была первоапрельской шуткой, которая стала популярной и превратилась в серьезное приложение.
Изучите Python на Хекслете Пройдите нашу профессию «Python-разработчик», чтобы поменять свою жизнь и стать бэкенд-программистом.
Плюсы и минусы Flask
Практически все плюсы и минусы Flask появились именно из-за того, что он является микрофреймворком.
- Простота. Flask легко установить и настроить.
- Гибкость. Микрофреймворк позволяет разработчикам самостоятельно выбирать технологии и инструменты, которые они хотят применять в своих проектах
- Расширяемость. Flask позволяет расширять функциональность с помощью плагинов и модулей, которые можно легко интегрировать в проект.
- Активное сообщество. Flask является одним из самых используемых фреймворков для Python, поэтому имеет большое комьюнити разработчиков.
При этом у Flask есть и свои недостатки:
- Отсутствие готовых решений. Разработчики изначально могут использовать во Flask только минимальный набор функциональности. Если же программисту нужны более широкие возможности, такие как аутентификация пользователя, ему придется добавить дополнительные библиотеки или реализовать это самостоятельно.
- Нет встроенной многопоточности. Flask был разработан как однопоточный фреймворк. И чтобы управлять многопоточными веб-приложениями, придется установить дополнительные библиотеки.
- Ограниченные возможности для масштабирования. Если проект начинает расти и усложняться, то могут появиться сложности в поддержке нужной функциональности.
То есть Flask можно удобно использовать в небольших проектах — он идеален для макетирования идей и быстрого прототипирования. При этом его редко используют в крупных проектах, и он плохо подходит для асинхронного программирования.
Как создать проект на Flask
Для начала работы с микрофреймворком нужно скачать последнюю версию Flask:
pip install Flask
Для примера мы напишем на Flask тестовое веб-приложение с минимальным функционалом. Как работают приложения такого типа:
- Пользователь вводит в браузере url, например — hexlet.io. В нашем тестовом приложении пользователь не будет вводить url, потому что мы будем работать с локальным сервером по адресу http://127.0.0.1:5000 .
- Браузер получает у DNS IP-адрес нужного нам сервера. DNS — это Domain Name System, распределенная системе серверов. Она работает как общая «контактная книга» в интернете.
- Браузер отправляет запрос по этому адресу и получает ответ. Как правило — в виде HTML-страницы.
- Браузер отображает содержимое страницы.
Итак, создадим файл hello.py и запишем в него следующий код:
from flask import Flask app = Flask(__name__) @app.route('/') def index() -> str: return 'Hello Flask!
' if __name__ == '__main__': app.run(debug=True)
Давайте подробно разберем, что делает код, который мы написали.
Первой строкой мы импортируем класс Flask . После этого мы создаем объект этого класса, передав первым аргументом имя модуля, — это и будет наше приложение для общения с веб-cервером. __name__ — это удобный способ передать именно то приложение, из которого запущен Flask.
Декоратор route() сообщает Flask, при обращении к какому URL-адресу запустится декорируемая разработчиком функция — в нашем примере это index . Последней строчкой мы открываем локальный веб-сервер с параметром debug=True — это позволит следить за всеми ошибками в логе программы.
Читайте также: Программирование на Python: особенности обучения, перспективы, ситуация на рынке труда
Запускаем веб-приложение через терминал:
Если мы все сделали правильно, то в терминале появятся эти сообщения:

В основном тут отображается служебная информация. Единственное, что нас интересует — сообщение, что наш локальный сервер запущен по адресу http://127.0.0.1:5000/ . В нем красными буквами указывается, что локальный сервер не подходит для продакшена. Но, так как мы реализовали тестовое приложение, то не будем деплоить его на реальный сервер.
Вернемся к коду. С помощью переменной части маршрута Flask может передавать в функцию аргументы.
from flask import Flask app = Flask(__name__) @app.route('/') def index(): greet_with_link = """Привет, Мир!
Нажми на меня
""" return greet_with_link @app.route('/user//') def get_user(name, surname): personal_instruc = f"""Привет,
surname> name>! Измени имя пользователя в адресной строке и перезагрузи страницу
""" return personal_instruc if __name__ == '__main__': app.run(debug=True)
В нашем примере значения просто появятся в браузере как часть строки. На стартовой странице нашего сайта будет запускаться функция index() . В ней пользователю, помимо приветствия, будет предлагаться нажать на ссылку, при клике на которую он перейдет на user/Аникин/Георгий . Этот URL-маршрут будет обрабатываться уже функцией get_user .
Функция get_user декорируется @app.route(‘//’) , а в адресной строке у нас /user/Аникин/Георгий . То есть наша функция получает аргументы из URL-адреса, эти значения лежат между косых скобок. По умолчанию тип таких значений string принимает любой текст без косой черты. Но переменные маршрутов могут быть и иных типов: int , float , path и других. Типы указываются в формате .
Структура приложения на Flask
Создадим подкаталог flask_app с такой структурой файлов и папок:

Чтобы написать приложение сложнее одной строки, в директории проекта должны находиться папки static и templates . Директория static содержит ресурсы, которые используются шаблонами. В том числе включая файлы CSS, JavaScript и картинки. Папка templates содержит только шаблоны с расширением *.html .
Заполним наши файлы кодом. Сначала — наш основной файл проекта app.py :
from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): return render_template("index.html") @app.route("/about") def get_page_about(): return render_template("about.html") if __name__ == "__main__": app.run(debug=True)
После этого — index.html :
Main page Главная страница
И файл about.html :
About О приложении
Для отображения HTML-шаблонов мы используем функцию render_template() . В нашем коде она принимает только имя шаблона и возвращает строку с результатом рендеринга шаблона.
Однако render_template() может принимать неограниченное количество именованных аргументов, которые можно использовать в этом шаблоне. Это позволит решить проблему нашего тестового проекта — сейчас у нас две функции, две страницы, и очень много дублированного кода.
Напишем базовый шаблон base.html и пару его наследников. При этом блоки … — это части базового шаблона, которые можно заменить в наследнике. Переменные передаются по именам в конструкции > .
Приложение Flask >
После появления файла с базовым HTML-шаблоном можем поправить наши остальные HTML-файлы:
About index.html: Main page
Кроме того, нужно поправить и основной файл Flask-проекта app.py :
from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): return render_template("index.html", h1 = "Главная страница") @app.route("/about") def get_page_about(): return render_template("about.html", h1 = "О приложении") if __name__ == "__main__": app.run(debug=True)
Подключаем Bootstrap
Bootstrap — это открытый и бесплатный набор инструментов для создания сайтов и веб-приложений.
В нашем проекте в папке templates у нас есть подкаталог bootstrap , а в нем файл base.html — это немного модифицированная заготовка сайта-документации Bootstrap-Flask:
lang="en"> charset="utf-8"> name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> > Приложение Flask class="jumbotron text-center"> > >
В файлах index.html и about.html заменим строку наследования на:
Второй путь подключения Bootstrap к проекту на Flask — через CDN. Подробнее об этом можно почитать в документации фреймворка .
Читайте также: Как создатель Python Гвидо ван Россум устроился в Microsoft и теперь работает над развитием CPython
После подключения Bootstrap нужно будет немного поправить основной файл нашего проекта app.py :
from flask_bootstrap import Bootstrap4 from flask import Flask, render_template app = Flask(__name__) bootstrap = Bootstrap4(app) @app.route("/") def index(): return render_template("index.html", h1 = "Главная страница") @app.route("/about") def get_page_about(): return render_template("about.html", h1 = "О приложении") if __name__ == "__main__": app.run(debug=True)
Последним элементом нашего веб-приложения будет форма отправки. Для этого нужно немного модифицировать index.html :
Main page > class="container text-center"> class="d-inline-block" style="max-width: 33%;"> class="form-group"> for="eventDate">Дата type="date" name="eventDate" class="form-control" placeholder="Дата события"> class="form-group"> for="eventName">Событие type="text" name="eventName" class="form-control" placeholder="Название события"> class="form-group"> for="eventDuration">Продолжительность type="number" name="eventDuration" class="form-control" placeholder="Продолжительность" min="1" max="24"> type="submit" class="btn btn-primary">Записать
Вообще, Bootstrap может добавить огромное количество элементов в приложение буквально в несколько кликов. Мы ограничились четырьмя — три поля и одна кнопка. Ключевой элемент здесь — это > .
Подключаем базу данных
Итак, у нас есть форма отправки, но она пока ничего не делает с данными. Для нас было бы неплохо хранить, обрабатывать и в будущем легко извлекать данные этих форм. Обычно такие задачи решают с помощью реляционных баз данных (далее БД).
Есть большое количество способов работы с SQL-запросами во Flask. Мы можем использовать, например, sqlite3 и чистый SQL, а можем — библиотеку sqlite3 для Python. Кроме того, можно обернуть чистые SQL-запросы в код, либо использовать Psycopg2 для работы с PostgresSQL в Python (мы рекомендуем делать именно так и вот почему). Для примера в этом тексте мы используем библиотеку Flask SQLAlchemy (расширение для Flask), которая предлагает технологию ORM для взаимодействия с БД.
Подключаем базу данных к нашему проекту через файл app.py :
from datetime import datetime from flask import Flask, redirect, render_template, request from flask_bootstrap import Bootstrap4 from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) bootstrap = Bootstrap4(app) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///events.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class Event(db.Model): id = db.Column(db.Integer, primary_key=True) date = db.Column(db.Date, nullable=False) name = db.Column(db.String(255), nullable=False) duration = db.Column(db.Integer, nullable=False) def __str__(self): return ( f"Название: self.name>\n" f"Дата: self.date>\n" f"Продолжительность self.duration>ч" ) @app.route('/', methods=['POST']) def add_event(): date = datetime.strptime(request.form['eventDate'], '%Y-%m-%d').date() name = request.form['eventName'] duration = int(request.form['eventDuration']) print(date, name, duration, sep='\n') event = Event(date=date, name=name, duration=duration) db.session.add(event) db.session.commit() return redirect('/') @app.route("/") def index(): return render_template("index.html", h1 = "Главная страница") @app.route("/about") def get_page_about(): return render_template("about.html", h1 = "О приложении") if __name__ == "__main__": with app.app_context(): db.create_all() app.run(debug=True)
В нашей БД появился класс Event c атрибутами, который наследуется от db.Model . Это позволяет с помощью SQLAlchemy создать таблицу event , а поля нашего класса сделать колонками этой таблицы. Кроме того, мы определили магический метод __str__ для строкового отображения экземпляров класса — это пригодится для отображения в HTML.
Для создания таблицы в блок if __name__ == ‘__main__’ мы добавили команду db.create_all() , а для обработки отправленной формы — метод add_event . Он работает с методом POST , который указывает Flask, что данные будут отправлены на сервер.
В методе POST мы считываем данные отправленной формы и создаем для каждой строки временную переменную. После этого мы создаем объект event класса Event , передаем наши временные переменные как именованные аргументы, добавляем event в БД и фиксируем изменения.
Нам осталось лишь немного поправить форму: в файле index.html в открывающем теге добавим атрибуты action=»>» method=»POST» . Теперь форма отправки по нажатию на кнопку «Записать» будет отправлять данные в базу данных.
Добавим страницу отображения наших записей в новый файл Events.html :
Events > class="container text-center"> href=">"> Добавить событие class="mt-4"> class="list-group"> class="list-group-item"> >
В файл app.py добавим view :
@app.route("/events") def view_events(): events = Event.query.order_by(Event.date).all() return render_template("events.html", h1 = "События", events=events)
А в основном контейнере index.html добавим ссылку на эту страницу:
Наш тестовый проект на Flask готов! Его можно запустить на локальном сервере через команду python app.py (в некоторых случаях надо будет написать название директории перед названием файла app.py ).
Что еще почитать про Flask
- Большой курс по Flask на Хекслете
- Документация Flask
- Цикл статей на Real Python
- Проектирование RESTful API с помощью Python и Flask
Изучите Python на Хекслете Пройдите нашу профессию «Python-разработчик», чтобы поменять свою жизнь и стать бэкенд-программистом.
#3 Основы Flask
Начать знакомство с Flask можно с создания простого приложения, которое выводит “Hello World”. Создаем новый файл main.py и вводим следующий код.
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello World' if __name__ == "__main__": app.run()
Это приложение “Hello World”, созданное с помощью фреймворка Flask. Если код в main.py не понятен, это нормально. В следующих разделах все будет разбираться подробно. Чтобы запустить main.py , нужно ввести следующую команду в виртуальную среду Python.
(env) gvido@vm:~/flask_app$ python main.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Запуск файла main.py запускает локальный сервер для разработки на порте 5000. Осталось открыть любимый браузер и зайти на https://127.0.0.1:5000/ , чтобы увидеть приложение Hello World в действии.
Остановить сервер можно с помощью комбинации CTRL+C.
Создание приложения Flask
У каждого Flask-приложения должен быть экземпляр класса. Экземпляр — это WSGI-приложение (WSGI – это интерфейс для взаимодействия сервера с фреймворком), которое показывает, что сервер передает все полученные запросы экземпляру для дальнейшей обработки. Объект класса Flask создается следующим образом:
from flask import Flask app = Flask(__name__)
В первой строке класс Flask импортируется из пакета flask .
Во второй строке создается объект Flask . Для этого конструктору Flask назначается аргумент __name__ . Конструктор Flask должен иметь один обязательный аргумент. Им служит название пакета. В большинстве случаев значение __name__ подходит. Название пакета приложения используется фреймворком Flask, чтобы находить статические файлы, шаблоны и т. д.
Создание route (путей)
Маршрут (или путь) используется во фреймворке Flask для привязки URL к функции представления. Эта функция отвечает на запрос. Во Flask декоратор route используется, чтобы связать URL адрес с функций. Вот как маршрут создается.
@app.route('/') def index(): return 'Hello World'
Этот код назначает функцию index() обработчиком корневого URL в приложении. Другими словами, каждый раз, когда приложение будет получать запрос, где путь — / , вызывается функция index() , и на этом запрос завершается.
Как вариант можно использовать метод add_url_rule() вместо декоратора route для маршрутизации. add_url_rule() — это простой метод, а не декоратор. Помимо URL он принимает конечную точку и название функции представления. Конечная точка относится к уникальному имени маршрута. Обычно, название функции представления — это и есть конечная точка. Flask может генерировать URL из конечной точки, но об этом позже. Предыдущий код аналогичен следующему:
def index(): return 'Hello World' app.add_url_rule('/', 'index', index)
Декоратор route используется в большинстве случаев, но у add_url_rule() есть свои преимущества.
Функция представления должна вернуть строку. Если пытаться вернуть что-то другое, сервер ответит ошибкой 500 Internal Sever Error.
Можно создать столько столько, сколько нужно приложению. Например, в следующем списке 3 пути.
@app.route('/') def index(): return 'Home Page' @app.route('/career/') def career(): return 'Career Page' @app.route('/feedback/') def feedback(): return 'Feedback Page'
Когда URL в маршруте заканчивается завершающим слешем ( / ), Flask перенаправляет запрос без слеша на URL со слешем. Так, запрос к /career будет перенаправлен на /career/ .
Для одной функции представления может быть использовано несколько URL. Например:
@app.route('/contact/') @app.route('/feedback/') def feedback(): return 'Feedback Page'
В этом случае в ответ на запросы /contact/ или /feedback/ , будет вызвана функция feedback() .
Если перейти по адресу, для которого нет соответствующей функции представления, появится ошибка 404 Not Found.
Эти маршруты статичны. Большая часть современных приложений имеют динамичные URL. Динамичный URL – это адрес, который состоит из одной или нескольких изменяемых частей, влияющих на вывод страницы. Например, при создании веб-приложения со страницами профилей, у каждого пользователя будет уникальный id. Профиль первого пользователя будет на странице /user/1 , второго — на /user/2 и так далее. Очень неудобный способ добиться такого результата — создавать маршруты для каждого пользователя отдельно.
Вместе этого можно отметить динамические части URL как (переменные). Эти части потом будут передавать ключевые слова функции отображения. Следующий код демонстрирует путь с динамическим элементом.
@app.route('/user//') def user_profile(id): return "Profile page of user #<>".format(id)
В этом примере на месте будет указываться часть URI, которая идет после /user/ . Например, если зайти на /user/100/ , ответ будет следующим.
Profile page of user #100
Этот элемент не ограничен числовыми id. Адрес может быть /user/cowboy/ , /user/foobar10/ , /user/@@##/ и так далее. Но он не будет работать со следующими URI: /user/ , /user/12/post/ . Можно ограничить маршрут, чтобы он работал только с числовыми id после /user/ . Это делается с помощью конвертера.
По умолчанию динамические части URL передаются в функцию в виде строк. Это можно изменить с помощью конвертера, который указывается перед динамическими элементами URL с помощью . Например, /user// будет работать с адресами /user/1/ , /user/200/ и другими. Но /user/cowboy/ , /user/foobar10/ и /user/@@##/ не подойдут.
В этом списке все конвертеры, доступные во Flask:
| Конвертер | Описание |
|---|---|
| string | принимает любые строки (значение по умолчанию). |
| int | принимает целые числа. |
| float | принимает числа с плавающей точкой. |
| path | принимает полный путь включая слеши и завершающий слеш. |
| uuid | принимает строки uuid (символьные id). |
Запуск сервера
Для запуска сервера разработки нужно использовать метод run() объекта Flask .
if __name__ == "__main__": app.run()
Условие __name__ == «__main__» гарантирует, что метод run() будет вызван только в том случае, если main.py будет запущен, как основная программа. Если попытаться использовать метод run() при импорте main.py в другой модуль Python, он не вызовется.
Важно: сервер разработки Flask используется исключительно для тестирования, поэтому его производительность невысокая.
Теперь должно быть понятнее, как работает main.py .
Режим отладки (Debug)
Баги неизбежны в программировании. Поэтому так важно знать, как находить ошибки в программе и исправлять их. Во Flask есть мощный интерактивный отладчик, который по умолчанию отключен. Когда он выключен, а в программе обнаруживается ошибка, функция показывает 500 Internal Sever Error. Чтобы увидеть это поведение наглядно, можно специально добавить баг в файл main.py .
from flask import Flask app = Flask(__name__) @app.route('/') def index(): print(i) return 'Hello World' if __name__ == "__main__": app.run()

В этом случае программа пытается вывести значение неопределенной переменной i, что приводит к ошибке. Если открыть https://127.0.0.1:5000/ , то появится ошибка 500 Internal Sever Error:
Тем не менее сам браузер не сообщает о типе ошибки. Если посмотреть в консоль, то можно увидеть отчет об ошибке. В данном случае он выглядит вот так:
File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request rv = self.dispatch_request() File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "main.py", line 13, in index print(i) NameError: name 'i' is not defined
Когда режим отладки выключен, после изменения кода нужно каждый раз вручную запускать сервер, чтобы увидеть изменения. Но режим отладки будет перезапускать его после любых изменений в коде.
Чтобы включить режим, нужно передать аргумент debug=True методу run() :
if __name__ == "__main__": app.run(debug=True)
Еще один способ — указать значение True для атрибута debug .
from flask import Flask app = Flask(__name__) app.debug = True
После обновления файл main.py следующим образом его можно запускать.
from flask import Flask app = Flask(__name__) @app.route('/') def index(): print(i) return 'Hello World' if __name__ == "__main__": app.run(debug=True) # add debug mode
Теперь при открытии https://127.0.0.1:5000/ на странице будет отладчик.
Теперь, когда отладчик включен, вместо ошибки 500 Internal Server на странице будет отображаться отчет об ошибке. Он в полной мере описывает, какая ошибка случилась. Внизу страницы видно, что оператор print пытался вывести значение неопределенной переменной i . Там же указан тип ошибки, NameError , что подтверждает то, что ошибка заключается в том, что имя i не определено.
Кликнув на строчку кода на странице вывода ошибки, можно получить исходный код, где эта ошибка обнаружена, а также предыдущие и следующие строчки. Это помогает сразу понять контекст ошибки.

При наведении на строчку кода отображается иконка терминала. Нажав на нее, откроется консоль, где можно ввести любой код Python.

В ней можно проверить локальные переменные.

Если консоль открывается первый раз, то нужно ввести PIN-код.

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

Завершить урок стоит созданием еще одного приложения Flask с применением всех имеющихся знаний.
Создаем еще один файл main2.py со следующим кодом:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello Flask' @app.route('/user//') def user_profile(user_id): return "Profile page of user #<>".format(user_id) @app.route('/books//') def books(genre): return "All Books in <> category".format(genre) if __name__ == "__main__": app.run(debug=True)
Если запустить файл и зайти на https://127.0.0.1:5000/ , браузер поприветствует выражением «Hello Flask»:

В этой новой версии приложения есть два динамических пути. Если в браузере ввести https://127.0.0.1:5000/user/123/ , откроется страница со следующим содержанием:

Стоит заметить, что путь /user// будет работать только с теми URL, где динамическая часть ( user_id ) представлена числом.
Чтобы проверить второй динамический путь, нужно открыть https://127.0.0.1:5000/books/sci-fi/ . В этот раз получится следующее:

Если сейчас попробовать открыть URL, который не определен в путях, выйдет ошибка 404 Not Found. Например, такой ответ получите при попытке перейти на https://127.0.0.1:5000/products .
Как Flask обрабатывает запрос?
Откуда Flask знает, какую функцию выводить, когда он получает запрос от клиента?
Flask сопоставляет URL и функции отображения, которые будут выводиться. Определение соответствий (маршрутизация) создается с помощью декоратора route или метода add_url_rule() в экземпляре Flask. Получить доступ к этим соответствиям можно с помощью атрибута url_map у экземпляра Flask .
>>> >>> from main2 import app >>> app.url_map Map([Rule '/' (OPTIONS, GET, HEAD) -> index>, Rule '/static/' (OPTIONS, GET, HEAD) -> static>, Rule '/books/' (OPTIONS, GET, HEAD) -> books>, Rule '/user/' (OPTIONS, GET, HEAD) -> user_profile>]) >>>
Как видно, есть 4 правила. Flask определяет соответствия URL в следующем формате:
url pattern, (comma separated list of HTTP methods handled by the route) -> view function to execute
Путь /static/ автоматически добавляется для статических файлов Flask. О работе со статическими файлами речь пойдет в отдельном уроке «Обслуживание статических файлов во Flask».
- ТЕГИ
- Flask
- Уроки по Flask на русском
Декоратор @route() и метод add_url_rule() приложения Flask Python
Декоратор @app.route() и метод app.add_url_rule() регистрируют URL-адрес, по которому будет доступно соответствующее представление и вызываются экземпляром приложения app фреймворка Flask.
Содержание:
- Декоратор экземпляра приложения @app.route() .
- Метод экземпляра приложения app.add_url_rule() .
- Список аргументов @app.route() и app.add_url_rule() .
@app.route(rule, **options) :
Декоратор @app.route() регистрирует URL-адрес, по которому будет доступно соответствующее представление (расположенное под декоратором), а так же правила маршрутизации входящих запросов. Этот декоратор вызывает метод app.add_url_rule() , реализация которого рассматривается более подробно.
@app.route("/") def index(): return "Hello, World!"
Правила маршрутизации входящих запросов (переменные части маршрута) указанные в угловых скобках передаются в соответствующую функцию-представление в качестве аргументов.
@app.route("`//`") def user(user, username): return f"Hello, username>! ID-user: user>"
Если аргумент endpoint не определен, то по умолчанию в качестве имени конечной точки для маршрута используется имя функции-представления.
Подробное описание аргументов, которые принимает декоратор @app.route() смотрите ниже.
Декоратор @app.route() вызывается экземпляром приложения фреймворка Flask.
app.add_url_rule(rule, endpoint=None, view_func=None, provide_automatic_options=None, **options) :
Метод app.add_url_rule() регистрирует URL-адрес, по которому будет доступно соответствующее представление, а так же правила маршрутизации входящих запросов. Декоратор @app.route() — это ссылка для вызова этого метода с аргументом view_func (функция-представление). Они эквивалентны:
@app.route("/") def index(): . # эквивалентно def index(): . app.add_url_rule("/", view_func=index)
Правила маршрутизации входящих запросов (переменные части маршрута), указанные в угловых скобках, передаются в соответствующую функцию-представление в качестве аргументов.
def index(id): . app.add_url_rule("/user/", view_func=index)
Если аргумент endpoint не передан, то по умолчанию, в качестве имени конечной точки маршрута используется имя функции-представления. Если функция-представление уже была зарегистрирована для конечной точки, то будет вызвана ошибка.
По умолчанию для аргумента methods установлено значение [‘GET’] . HTTP-метод HEAD всегда добавляется автоматически, а HTTP-метод OPTIONS добавлен в настройках по умолчанию.
Аргумент view_func не всегда нужно передавать, но если правило участвует в маршрутизации, то имя конечной точки endpoint должно быть связано с функцией-представлением декоратором @app.endpoint() .
app.add_url_rule("/", endpoint="index") @app.endpoint("index") def index(): .
Если функция-представления имеет атрибут required_methods , то HTTP-методы, указанные в этом атрибуте, добавляются к переданным в app.add_url_rule() HTTP-методам. Если у функции-представления есть атрибут provide_automatic_options , то он используется по умолчанию, если одноименный аргумент не определен.
def index(): if request.method == 'OPTIONS': # обработка запроса . return 'Hello World!' # присваиваем атрибуты функции-представлению index.provide_automatic_options = False index.methods = ['GET', 'OPTIONS'] # атрибуты функции `index()` передаются # в качестве аргументов app.add_url_rule('/', index)
Подробнее об атрибутах, которые может иметь функция-представление, смотрите в материале «Представления в веб-приложении на Flask».
Список аргументов декоратора @app.route() и метода app.add_url_rule() .
Ниже приведены аргументы, которые принимают декоратор @app.route() и метод app.add_url_rule() . Единственное отличие состоит в том, что аргумент view_func в декораторе @app.route() отсутствует, так как за декоратором следует функция-представление, которая и заменяет этот аргумент.
- rule : правило URL-адреса в виде строки;
- endpoint : конечная точка для зарегистрированного правила URL-адреса. Сам Flask предполагает, что имя функции-представления является именем конечной точки, если явно она не задана;
- view_func : функция, вызываемая при обслуживании запроса к предоставленной конечной точке. Если это не предусмотрено, то можно указать функцию позже, сохранив ее в словаре view_functions с конечной точкой в качестве ключа.
- defaults : словарь с настройками по умолчанию для этого правила.
@app.route('/users/', defaults='page': 1>) @app.route('/users/page/') def show_users(page): pass
from flask import Flask app = Flask(__name__, subdomain_matching=True) app.config['SERVER_NAME'] = "example.com" @app.route("/") def index(): return "example.com" @app.route("/", subdomain="") def sub_index(subdomain): return f'subdomain>.example.com'
- methods=[‘GET’] : это список методов, которым должен быть ограничен маршрут ( GET , POST и т. д.). По умолчанию правило просто прослушивает GET (и неявно HEAD ). Начиная с Flask 0.6, OPTIONS неявно добавляются и обрабатываются стандартными запросами.
- redirect_to : если задано, то это должно быть либо строка URL, либо вызываемая функция-представление. В случае вызываемого объекта, он вызывается с адаптером URL, который инициировал сопоставление, и значениями URL в качестве ключевых аргументов и должны возвращать цель для перенаправления, в противном случае это должна быть строка маршрута:
# Функция, которая генерирует новые URL-адреса def foo_with_slug(adapter, id): # запросить в базе данных `id` для старого идентификатора. return f'foo/Foo.get_slug_for_id(id)>' @blueprint.route('/foo/') def all(page): . # правила перенаправлений на новые URL-адреса app.add_url_rule('/some/old/url/', redirect_to='foo/') app.add_url_rule('/other/old/url/', redirect_to=foo_with_slug)
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Пример структуры приложения Flask как пакета Python
- Модульные приложения на схемах blueprint во Flask Python
- Фабрика веб-приложений модуля Flask
- Представления в веб-приложении на Flask Python
- Правила составления URL-маршрутов во Flask Python
- Использование шаблонизатора Jinja2 в приложении Flask Python
- Пользовательские страницы HTTP-ошибок на Flask Python
- Выполнение кода до или после запроса во Flask Python
- Загрузка файлов на сервер во Flask Python
- Всплывающие сообщения в приложении на Flask Python
- Извлечение данных из запроса во Flask Python
- Хранение и загрузка конфигураций Flask
- Параметры/ключи конфигурации, используемые во Flask
- Папки экземпляров приложений на Flask
- Контекст веб-приложения на Flask
- Контекст запроса приложения на Flask
- Ведение журнала логов в приложении Flask Python
- Собственные декораторы в приложении Flask Python
- Класс Config() модуля flask
- Функция redirect модуля flask
- Функция url_for() модуля flask
- Прокси-объект current_app() модуля flask
- Функция abort() модуля flask
- Отладочные сигналы приложения Flask
- Работа с cookie в приложении на Flask Python
- Безопасность веб-приложения на Flask
- Асинхронность в веб-приложении на Flask
- Использование URL-процессора в приложениях на Flask Python
- Диспетчеризация приложений на Flask
- Функция make_response модуля flask
- Доступность контекстов запроса/приложения во Flask Python
- Декоратор @route() и метод add_url_rule() приложения Flask Python
- Функция send_file() модуля flask
- Функция send_from_directory() модуля flask
- Как обслуживать статические файлы в Flask Python
- Функция render_template() модуля flask
- Класс Markup() модуля flask
- Отложенная загрузка представлений в приложении Flask Python
- Сессии/сеансы sessions модуля flask
- Глобальный объект flask.g в приложении Flask Python
- Класс Request() модуля flask
- Класс Response() модуля flask
- Класс Flask() модуля flask
- Тестирование приложений на Flask
- Использование SQLite 3 в приложении Flask Python
- Генерация своей капчи на сайте Flask
- Использование модуля WTForms в приложении Flask Python
- Расширение Flask-Caching для приложения Flask
- Расширение Flask-Assets, управление статикой приложения
- Расширение Flask-WTF для приложения Flask
- Расширение Flask-SQLAlchemy для приложения Flask
- Расширение Flask-Paginate для приложения Flask
- Расширение Flask-Mail для приложения Flask
- Расширение Flask-APScheduler
- Связка Nginx + Gunicorn + Gevent + Flask Python
- Как передать переменную NGINX во Flask environ
- Защита приложения/сайта от DDoS атак