Flask: различия между версиями

Содержимое удалено Содержимое добавлено
м <source> -> <syntaxhighlight> (phab:T237267)
Строка 41:
== Простейший Hello world ==
Создадим файл hello.py следующего содержания:
<sourcesyntaxhighlight lang="python">
from flask import Flask
app = Flask(__name__)
Строка 51:
if __name__ == "__main__":
app.run()
</syntaxhighlight>
</source>
 
Проверим как установился Flask. Запустим скрипт:<br />
Строка 92:
Современные веб-приложения имеют красивые URL. Это помогает людям помнить их, особенно это удобно для приложений, которые используются в мобильных устройствах с медленным сетевым подключением. Если пользователь может попасть на страницу через URL минуя главную страницу, то более вероятно, что он вернется в следующий раз.<br />
Как вы видели выше, декоратор route() используется для связывания функций с URL. Вот несколько основных примеров:
<sourcesyntaxhighlight lang="python">
@app.route('/')
def index():
return 'Index Page'
</syntaxhighlight>
</source>
 
 
<sourcesyntaxhighlight lang="python">
@app.route('/hello')
def hello():
return 'Hello World'
</syntaxhighlight>
</source>
Но это еще не все! Вы можете сделать некоторые части URL динамическими и применить несколько правил к функции.
 
=== Использование переменных ===
Для добавления переменной части в URL вы можете пометить эти разделы, как <variable_name>. Такая часть затем передается как аргумент ключевого слова в вашу функцию. Дополнительно преобразователь может быть определен путем указания правила <converter:variable_name>. Вот некоторые хорошие примеры:
<sourcesyntaxhighlight lang="python">
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
</syntaxhighlight>
</source>
 
 
<sourcesyntaxhighlight lang="python">
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
</syntaxhighlight>
</source>
 
Имеются следующие конверторы
Строка 136:
Линки во Flask основаны на базе модуля маршрутизации от Werkzeug. Идея этого модуля заключается в обеспечении красивых и уникальных URL-адресов на основе правил ранее сформировавшихся в Apache и в HTTP серверах.<br />
Используйте два правила:
<sourcesyntaxhighlight lang="python">
@app.route('/projects/')
def projects():
return 'The project page'
</syntaxhighlight>
</source>
<br />
<sourcesyntaxhighlight lang="python">
@app.route('/about')
def about():
return 'The about page'
</syntaxhighlight>
</source>
Хоть эти примеры и выглядят очень похоже, они различаются по слэшу в конце URL. В первом случае, доступ без слэша вызывает редирект на канонические URL с обратным слэшем.<br />
Во втором случае, без обратного слэша, URL определяется, как путь к файлу на UNIX-подобных системах. Доступ к URL со слэшем будет перенаправляться на ошибку 404 «не найдено».<br />
Строка 153:
=== Генерация URL ===
Flask может генерировать URL. Для создания URL, используйте функцию <code>url_for()</code>. Она принимает имя функции в качестве первого аргумента, а также ряд ключевых аргументов, каждый из которых соответствует переменной части URL правила. Части неизвестной переменной добавляется к URL в качестве параметров запроса. Вот несколько примеров:
<sourcesyntaxhighlight lang="python">
>>> from flask import Flask, url_for
>>> app = Flask(__name__)
Строка 175:
/login?next=/
/user/John%20Doe
</syntaxhighlight>
</source>
Здесь также используется метод test_request_context(), который объяснен ниже. Он говорит Flask, как нужно обрабатывать запрос, даже если мы взаимодействуем через шел Python. Почему мы используем построение URL вместо их жесткого задания в шаблонах? На то есть три хорошие причины:
* Реверсирование, зачастую является более описательным методом и позволяет изменять URL на одном дыхании.
Строка 183:
=== HTTP методы ===
HTTP (мы говорим о протоколе веб-приложения) знает различные способы доступа к URL-адресам. По умолчанию маршрут реагирует только на ответы GET-запросов, но это можно изменить путем предоставления методов, используя аргументы к декоратору route(). Вот несколько примеров:
<sourcesyntaxhighlight lang="python">
from flask import request
 
Строка 192:
else:
show_the_login_form()
</syntaxhighlight>
</source>
Если присутствует GET, тогда HEAD будет добавлен автоматически. Вам не нужно об этом заботиться. Также будьте уверены, что HEAD поддерживает HTTP RFC зависимости, так что вы можете полностью игнорировать HTTP спецификации.<br />
Если вы ничего не знаете про HTTP методы, приводим небольшую справку:
Строка 214:
Просто создайте папку с названием static в вашем пакете или рядом с модулем и она будет доступна в /static по применению.<br />
Для генерации адресов для статических файлов, используйте специальное имя 'static':
<sourcesyntaxhighlight lang="python">
url_for('static', filename='style.css')
</syntaxhighlight>
</source>
Файл будет доступен в файловой системе по пути <code>static/style.css</code>
 
Строка 223:
<br />
Чтобы создать шаблон, можно использовать метод render_template(). Все, что вам нужно сделать, — это указать имя шаблона и переменные, которые вы хотите передать в шаблоны как ключевые аргументы. Вот простой пример того, как сделать шаблон:
<sourcesyntaxhighlight lang="python">
from flask import render_template
 
Строка 230:
def hello(name=None):
return render_template('hello.html', name=name)
</syntaxhighlight>
</source>
Flask будет искать шаблоны в папке шаблонов. Таким образом, если ваше приложение представляет собой модуль, эта папка находится рядом с этим модулем, если же это пакет, то на самом деле внутри вашего пакета:<br />
Случай с модулем:
<sourcesyntaxhighlight lang="python">
/application.py
/templates
/hello.html
</syntaxhighlight>
</source>
 
Случай с пакетом:<br />
<sourcesyntaxhighlight lang="python">
/application
/__init__.py
/templates
/hello.html</sourcesyntaxhighlight>
Пример шаблона:
<sourcesyntaxhighlight lang="python">
<!doctype html>
<title>Hello from Flask</title>
Строка 254:
<h1>Hello World!</h1>
{% endif %}
</syntaxhighlight>
</source>
Внутри шаблонов, вы также имеете доступ к реквестам, сессиям и g-объектам, а также можете использовать get_flashed_messages() функцию. G-объекты, имеется ввиду, если вам необходимо сохранить информацию для ваших нужд, смотрите документацию [http://flask.pocoo.org/docs/patterns/sqlite3/#sqlite3 «Использование SQLite 3 во Flask»].<br />
Шаблоны особенно полезны, если используется наследование. [http://flask.pocoo.org/docs/patterns/templateinheritance/#template-inheritance Прочтите документацию как используется наследование в шаблонах.] Наследование в шаблонах позволяет сохранить некоторые элементы на каждой страницы (например: заголовок, навигация и футер).<br />
Строка 260:
<br /><br />
Вот пример, как работает класс разметки:
<sourcesyntaxhighlight lang="python">
>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Строка 268:
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'
</syntaxhighlight>
</source>
 
== Доступ к данным запроса ==
Строка 281:
Представьте, что контекст обрабатывает поток. Приходит запрос и веб-сервер решает породить новый поток (или что-то другое, основной объект может иметь дело с параллельными системами в отличие от потоков). Когда Flask начинает свою внутреннюю обработку запросов, он выясняет, какой текущий поток является активным контекстом и связывает текущее приложение и WSGI среду в этом контексте (потоке). Он делает это умно, таким образом, чтобы одно приложение может вызвать другое приложение без разрушения.<br />
Итак, что же это значит для вас? В принципе, пока вы тестируете, вы можете полностью это игнорировать. Но вы можете заметить, что код, который зависит от объекта запроса может внезапно сломаться, потому что нет объекта запроса. Решением является создание объекта запроса для себя и привязка его к контексту. Самое простое решение для тестирования, это использование контекст менеджера test_request_context() В сочетании с постановкой, он свяжет тестовый запрос, так что вы можете взаимодействовать с ним. Вот пример:
<sourcesyntaxhighlight lang="python">
from flask import request
 
Строка 289:
assert request.path == '/hello'
assert request.method == 'POST'
</syntaxhighlight>
</source>
Другая возможность состоит в передаче всей WSGI среды к методу request_context():
<sourcesyntaxhighlight lang="python">
from flask import request
 
with app.request_context(environ):
assert request.method == 'POST'
</syntaxhighlight>
</source>
 
=== Объект запроса ===
Объект запроса описан в разделе API, и мы не будем рассматривать его здесь подробно (см. [http://flask.pocoo.org/docs/api/#flask.request запрос]). Вот широкий обзор некоторых из наиболее распространенных операций. Прежде всего вы должны импортировать <code>request</code> из Flask:
<sourcesyntaxhighlight lang="python">
from flask import request
</syntaxhighlight>
</source>
В настоящее время метод запроса доступен с использованием атрибута <code>method</code>. Чтобы получить доступ к данным формы (данным, передаваемым в POST или PUT запросе), вы можете воспользоваться атрибутом <code>form</code>. Вот полный пример двух атрибутов, упомянутых выше:
<sourcesyntaxhighlight lang="python">
@app.route('/login', methods=['POST', 'GET'])
def login():
Строка 316:
# this is executed if the request method was GET or the
# credentials were invalid
</syntaxhighlight>
</source>
Что произойдет, если ключ не существует в виде атрибута? В этом случае выбрасывается исключение <code>KeyError</code>. Вы можете поймать его как обычный <code>KeyError</code>, но если вы не сделаете этого, то вы увидите страницу с ошибкой HTTP 400 Bad Request. Таким образом, для многих ситуаций, вам не придется иметь дело с этой проблемой.
 
Чтобы получить доступ к параметрам, указанным в URL (?key=value), Вы можете использовать атрибут <code>args</code>:
<sourcesyntaxhighlight lang="python">
searchword = request.args.get('q', '')
</syntaxhighlight>
</source>
Мы рекомендуем получать доступ к URL параметрам с использованием метода <code>get</code> или отлавливать <code>KeyError</code>, потому что пользователи могут изменить URL. Страница 400 bad request page в этом случае выглядит не дружественно.
 
Строка 328:
Через Flask легко использовать загрузку файлов. Просто убедитесь, что не забыли поставить атрибут <code>enctype="multipart/form-data"</code> в вашей HTML форме, иначе браузер не передаст файлы. <br />
Загруженные файлы сохраняются в память сервера или во временное хранилище в файловой системе. Вы можете получить доступ к этим файлам через атрибут <code>files</code> в объекте запроса. Каждый загруженный файл хранится в этом словаре. Он ведет себя так же, как стандартный объект <code>file</code> в Python, но имеет метод save(), который позволяет сохранить этот файл в файловую систему сервера. Вот простой пример, показывающий, как это работает:
<sourcesyntaxhighlight lang="python">
from flask import request
 
Строка 337:
f.save('/var/www/uploads/uploaded_file.txt')
...
</syntaxhighlight>
</source>
Если вы хотите знать, как файл был назван клиентом, перед тем как он был загружен в ваше приложение, вы можете получить доступ к файлу через атрибут <code>filename</code>. Однако имейте в виду, что это значение может быть фальсифицировано. Если вы все же хотите использовать имя файла, который дал клиент, для хранения файлов на сервере, лучше передать его через secure_filename(), который предлагает Werkzeug:
<sourcesyntaxhighlight lang="python">
from flask import request
from werkzeug import secure_filename
Строка 349:
f.save('/var/www/uploads/' + secure_filename(f.filename))
...
</syntaxhighlight>
</source>
 
=== Cookies ===
Доступ к куки осуществляется через их атрибут. Для установки кукис, используйте метод set_cookie в объектах запроса. Данный атрибут представляет собой словарь со всеми переданными клиентскими кукис. Если вы хотите использовать сессии, то не используете куки напрямую, вместо них лучше использовать сессии Flask, что добавит вам некоторую безопасность поверх кукис. <br /><br />
Чтение кукис:
<sourcesyntaxhighlight lang="python">
from flask import request
 
Строка 362:
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
</syntaxhighlight>
</source>
Запись кукис:
<sourcesyntaxhighlight lang="python">
from flask import make_response
 
Строка 372:
resp.set_cookie('username', 'the username')
return resp
</syntaxhighlight>
</source>
Обратите внимание, что куки устанавливаются в объектах ответа. Которые обычно возвращаются как строки и Flask конвертируют в их объекты. Если вы хотите влиять на этот процесс, то используйте функцию <code>make_response()</code>
 
== Редиректы и ошибки ==
Для перенаправления пользователей в другое место используйте функцию <code>redirect()</code> А чтобы прервать запрос рано с кодом ошибки используйте функцию <code>abort()</code>.
<sourcesyntaxhighlight lang="python">
from flask import abort, redirect, url_for
 
Строка 388:
abort(401)
this_is_never_executed()
</syntaxhighlight>
</source>
Это довольно бессмысленный пример, потому что пользователи будут перенаправлены со страницы индекса. Они не смогут получить доступ (получат ошибку 401 — отказано в доступе), но это показывает, как это работает.
<br /><br />
По умолчанию черно-белые страницы ошибок показываются в каждом коде ошибок. Если вы хотите настроить страницу ошибки, вы можете использовать декоратор <code>errorhandler()</code>
<sourcesyntaxhighlight lang="python">
from flask import render_template
 
Строка 398:
def page_not_found(error):
return render_template('page_not_found.html'), 404
</syntaxhighlight>
</source>
 
== Об ответах ==
Строка 407:
# Если ничего из этого не работает, Flask примет возвращаемые значения, как пригодные для применения в WSGI приложении и преобразует их в объекты-ответа.
Если вы хотите заполучить результаты объект-ответ внутри обзора, используйте функцию make_response()
<sourcesyntaxhighlight lang="python">
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
</syntaxhighlight>
</source>
Вам просто нужно обернуть возвращение выражения от make_response() и получить результат объекта, чтобы изменить его, а затем вернуть его обратно:
<sourcesyntaxhighlight lang="python">
@app.errorhandler(404)
def not_found(error):
Строка 419:
resp.headers['X-Something'] = 'A value'
return resp
</syntaxhighlight>
</source>
 
== Сеансы ==
Строка 425:
 
Для того, чтобы использовать сессии вы должны установить секретный ключ. Вот как работают сессии:
<sourcesyntaxhighlight lang="python">
from flask import Flask, session, redirect, url_for, escape, request
 
Строка 456:
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
</syntaxhighlight>
</source>
escape() — указывается в этом примере, так как в данном случае не используется шаблонизатор. <br /><br />
'''Как сгенерировать хороший секретный ключ?'''<br />
Самый простой и наиболее доступный способ, сделать это на основе генератора псевдослучайных чисел.
<sourcesyntaxhighlight lang="python">
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
</sourcesyntaxhighlight>
Небольшое замечание о кукисах основанных на базе сессий: Flask примет значение, положит в объект-сессию и сериализует их в кукисы. Если вы обнаружили, что некоторые значения не сохранились между запросами, то учтите, что кукисы на самом деле активны, и вы не получите четкое сообщение об ошибке, поэтому проверяйте размер куки в ваших ответах на странице по сравнению с размером, который поддерживается веб-браузерами.
 
Строка 475:
Вы можете оказаться в ситуации, когда вы имеете дело с данными, которые по идее должны быть правильными, но на самом деле это не так. Например, некоторый клиентский код, который посылает HTTP-запрос к серверу. Это может быть вызвано манипуляциями с данными со стороны пользователя, или падение клиентского кода. Вполне нормально ответить на это ошибкой 400 Bad Request, но бывают ситуации, когда несмотря на ошибку, код должен продолжать работать.<br />
Если вы хотите видеть, что произошло что-то подозрительное, используйте логирование.
<sourcesyntaxhighlight lang="python">
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
</syntaxhighlight>
</source>
[http://docs.python.org/library/logging.html Здесь можете ознакомится с документацией по логированию.]
 
== Подключение WSGI Middlewares ==
Если вы хотите добавить WSGI middleware в ваше приложение, вы можете обернуть его внутри WSGI приложения. Например, если вы хотите добавить middleware от Werkzeug в работе, чтобы обойти ошибки в lighttpd, вы можете сделать это следующим образом:
<sourcesyntaxhighlight lang="python">
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
</syntaxhighlight>
</source>
 
= Учебное пособие =
Строка 499:
== Шаг 0: Создание каталогов ==
Вначале создадим каталоги, необходимые Вашему приложению:
<sourcesyntaxhighlight lang="python">
/flaskr
/static
/templates
</syntaxhighlight>
</source>
 
Каталог <code>flaskr</code> не пакет Python, а лишь место размещения наших файлов. Непосредственно в эту папку поместим схему нашей базы данных и основной модуль. Файлы каталога <code>static</code> доступны для пользователей через HTTP, оттуда подгружаются css и javascript файлы. В каталоге <code>templates</code> Flask будет искать Jinja2-шаблоны, которые будут созданы в конце урока.
Строка 509:
== Шаг 1: Схема базы данных ==
Создадим базу данных. Это не сложно, для этого приложения хватит одной таблицы и поддержки только SQLite. Просто поместим файл следующего содержания:
<sourcesyntaxhighlight lang="python">
drop table if exists entries;
create table entries (
Строка 516:
text string not null
);
</sourcesyntaxhighlight> с именем <code>schema.sql</code> в только что созданный каталог <code>flaskr</code>.
 
Эта схема состоит из одной таблицы с названием <code>entries</code>. У каждой записи в таблице есть свой идентификатор <code>id</code>, заголовок <code>title</code> и текст <code>text</code>. <code>Id</code> — автоматически увеличивающееся натуральное число и первичный ключ. Два строковых значения не должны быть неопределёнными и пустыми (<code>not null</code>).
Строка 524:
 
В файле <code>flaskr.py</code>:
<sourcesyntaxhighlight lang="python">
# all the imports
import sqlite3
Строка 536:
USERNAME = 'admin'
PASSWORD = 'default'
</syntaxhighlight>
</source>
 
Теперь можно создать практическое приложение и инициализировать его с конфигурацией из того же файла <code>flaskr.py</code>:
<sourcesyntaxhighlight lang="python">
# create our little application :)
app = Flask(__name__)
app.config.from_object(__name__)
</syntaxhighlight>
</source>
 
<code>from_object()</code> проанализирует данный объект (если это строка, то импортирует её) и найдёт все переменные (в верхнем регистре), определённые там. В нашем случае, конфигурация была в нескольких строках кода, приведенных выше. Её можно поместить в отдельный файл.
 
Обычно, хорошей идеей будет загрузка определений из конфигурационного файла. Это может сделать <code>from_envvar()</code> вместо <code>from_object()</code>.
<sourcesyntaxhighlight lang="python">
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
</syntaxhighlight>
</source>
 
Для изменения значений по умолчанию таким способом можно установить в переменной окружения <code>FLASKR_SETTINGS</code> название конфигурационного файла для загрузки. Флаг <code>silent</code> («тихо, безмолвно») отключает вывод сообщений Flask при отсутствии такой переменной окружения.
Строка 559:
 
Добавим метод для подключения к указанной базе данных. Он может быть использован для соединения по запросу, а также из интерактивной оболочки Python или скрипта. Этот метод пригодится позже.
<sourcesyntaxhighlight lang="python">
def connect_db():
return sqlite3.connect(app.config['DATABASE'])
</syntaxhighlight>
</source>
 
Наконец, если нужно запустить этот файл в качестве отдельного приложения, просто добавим в конец строку, запускающую сервер:
<sourcesyntaxhighlight lang="python">
if __name__ == '__main__':
app.run()
</syntaxhighlight>
</source>
Для запуска приложения используйте команду <code>python flaskr.py</code>, выводящую сообщение о том, что сервер запустился, и адрес, по которому следует обращаться. Однако, открыв этот адрес в браузере, получим ошибку «404 Страница не найдена», ведь у нас пока нет содержимого для просмотра. Но на этом сосредоточимся чуть позже. Сначала нам нужна рабочая база данных.
 
Строка 576:
 
Такая схема может быть создана передачей файла <code>schema.sql</code> в <code>sqlite3</code>:
<sourcesyntaxhighlight lang="bash">sqlite3 /tmp/flaskr.db < schema.sql</sourcesyntaxhighlight>
 
Минусом этого решения является то, что для установки требуется приложение <code>sqlite3</code>, которое установлено не в каждой системе. Кроме того, нужно указать путь к базе данных, где можно сделать ошибку. Хорошая идея — добавить функцию, которая инициализирует базу данных в самом приложении.
 
Желая поступить так, сначала Вы должны импортировать функцию <code>contextlib.closing()</code> из пакета <code>contextlib</code>. При использовании Python 2.5 необходимо импортировать <code>with_statement</code> из пакета <code>__future__</code> (импорт из <code>__future__</code> всегда должен быть первым в списке):
<sourcesyntaxhighlight lang="python">
from __future__ import with_statement
from contextlib import closing
</syntaxhighlight>
</source>
 
Теперь мы можем создать функцию с названием <code>init_db()</code> для инициализации базы данных. Для этого используем функцию <code>connect_db</code>, определённую ранее.
<sourcesyntaxhighlight lang="python">
def init_db():
with closing(connect_db()) as db:
Строка 593:
db.cursor().executescript(f.read())
db.commit()
</syntaxhighlight>
</source>
 
<code>closing()</code> — вспомогательная функция, позволяющая сохранить соединение открытым до конца блока <code>with</code>. Метод <code>open_resource()</code> поддерживает эту функциональность из коробки, так что его можно использовать в этом блоке. Функция открывает файл по пути (ваш flaskr каталог) и позволяет читать из него. Мы используем её здесь для выполнения скрипта с подключением к базе данных.
Строка 600:
 
Теперь у нас появилась возможность создать базу данных в оболочке Python, импортировав и вызвав созданную функцию:
<sourcesyntaxhighlight lang="python">
>>> from flaskr import init_db
>>> init_db()
</syntaxhighlight>
</source>
 
=== Поиск и устранение неисправностей ===
Строка 612:
 
Flask предоставляет такую возможность декораторами <code>before_request()</code>, <code>after_request()</code> и <code>teardown_request()</code>:
<sourcesyntaxhighlight lang="python">
@app.before_request
def before_request():
Строка 620:
def teardown_request(exception):
g.db.close()
</syntaxhighlight>
</source>
 
Функции, отмеченные <code>before_request()</code> срабатывают до запроса и передаются без аргументов. Функции, отмеченные <code>after_request()</code> вызываются после запроса и передают ответ для отправки клиенту. Они должны вернуть объект-ответ (''response object'') или другой объект. Но их исполнение не гарантировано при возникновении исключительной ситуации, в таких случаях работают функции с декоратором <code>teardown_request()</code>. Их вызов происходит после того, как ответ был построен. Они не имеют права изменять запрос, их возвращаемые значения игнорируются. Если исключение произошло во время обработки запроса, оно передается для каждой функции, в противном случае, пропускается (передаётся <code>None</code>).
Строка 637:
Этот вывод показывает все записи сохраненные в базе данных. Он мониторит корневой каталог приложения и выбирает по заголовку и тексту из базы данных. Запись с наибольшим идентификатором (новейшая запись) будет сверху. Ряды возвращаемые от курсора являются кортежем с колонками, и выбираются специфично по запросу. Это хорошо для небольших приложений, как здесь, но вы можете конвертировать их в словарь. Если вы заинтересованы, чтобы сделать это, то посмотрите как это сделано в [http://flask.pocoo.org/docs/patterns/sqlite3/#easy-querying Easy Querying].<br />
Эта обзорная функция пропускает записи через словари в шаблоне show_entries.html и возвращает обработанное значение:
<sourcesyntaxhighlight lang="python">
@app.route('/')
def show_entries():
Строка 643:
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
</syntaxhighlight>
</source>
 
 
Строка 649:
 
Эта страницы позволяет залогиненному пользователю добавлять новые записи. Это просто ответ на POST-запрос. Форма для данных показывается на странице отображения записей (show_entries). Если все сработало как надо, мы показываем (flash()) сообщение и производим перенаправление на страницу отображения записей:
<sourcesyntaxhighlight lang="python">
@app.route('/add', methods=['POST'])
def add_entry():
Строка 659:
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
</syntaxhighlight>
</source>
 
Обратите внимание, что мы проверяем, залогинен ли пользователь, по ключу (ключ ''logged_in'' существует в пределах сессии и равен ''True'').
Строка 668:
=== Функции login и logout ===
Эти функции используются для входа и выхода пользователей сайта. Login проверяет имя пользователя и его пароль и устанавливает для сессии параметр ''logged_in''. Если вход пользователя произошел успешно, то значение этого параметра устанавливается равным ''True'', и пользователь перенаправляется обратно на страницу ''show_entries''. Кроме того, пользователю выдается сообщение о том, что он успешно зашел на сайт. Если же происходит ошибка, то шаблон страницы логина выдает сообщение об этом, и запрос к пользователю повторяется.
<sourcesyntaxhighlight lang="python">
@app.route('/login', methods=['GET', 'POST'])
def login():
Строка 682:
return redirect(url_for('show_entries'))
return render_template('login.html', error=error)
</syntaxhighlight>
</source>
 
В свою очередь, функция logout удаляет параметр ''logged_in'' из сессии. Здесь мы использовали следующий трюк: если мы будем использовать метод словаря (dict) ''pop()'', и передадим в него второй параметр (значение по умолчанию), то метод удалит ключ из словаря, если он там есть, и не сделает ничего, если его нет. Трюк полезен, потому что нам не нужно проверять, был залогинен ли пользователь.
<sourcesyntaxhighlight lang="python">
@app.route('/logout')
def logout():
Строка 691:
flash('You were logged out')
return redirect(url_for('show_entries'))
</syntaxhighlight>
</source>
 
== Шаг 6: Шаблоны ==
Строка 707:
Словарь '''session''' доступен на уровне шаблонов, и вы можете использовать его для проверки, залогинен ли пользователь. Обратите внимание, что в Jinja вы можете получать отсутствующие атрибуты и элементы объектов/словарей, так что следующий код будет работать, даже если в сессии отсутствует параметр ''logged_in'':
 
<sourcesyntaxhighlight lang="html4strict">
<!doctype html>
<title>Flaskr</title>
Строка 725:
{% block body %}{% endblock %}
</div>
</syntaxhighlight>
</source>
 
=== show_entries.html ===
Этот шаблон расширяет предыдущий шаблон ''layout.html'' и показывает сообщения нашего блога. Обратите внимание, что цикл ''for'' перебирает сообщения, которые мы передали через функцию '''render_template()'''. Так же мы выводим форму для функции ''add_entry'' и используем ''POST''-запрос.
<sourcesyntaxhighlight lang="html4strict">
{% extends "layout.html" %}
{% block body %}
Строка 751:
</ul>
{% endblock %}
</syntaxhighlight>
</source>
 
=== login.html ===
И наконец, шаблон для входа на сайт, который просто показывает пользователю форму логина:
<sourcesyntaxhighlight lang="html4strict">
{% extends "layout.html" %}
{% block body %}
Строка 770:
</form>
{% endblock %}
</syntaxhighlight>
</source>
 
 
Строка 776:
 
Теперь, когда все работает, самое время сделать наше приложение стильным. Просто создайте страницу стилей с названием ''style.css'' в папке ''static'', которую мы создали раньше:
<sourcesyntaxhighlight lang="css">
body { font-family: sans-serif; background: #eee; }
a, h1, h2 { color: #377BA8; }
Строка 795:
border: 1px solid #AACBE2; }
.error { background: #F0D6D6; padding: 0.5em; }
</syntaxhighlight>
</source>
 
== Бонус: тестируем приложение ==