Показаны сообщения с ярлыком flask. Показать все сообщения
Показаны сообщения с ярлыком flask. Показать все сообщения

27 октября 2012 г.

Изменяем заголовки по умолчанию в имейлах от Flask-Security

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

Однако с ним есть маленькая беда. Дело в том, что все заголовки писем, отправляемых при его помощи захардкожены как строки в коде, а для того или иного приложения есть смысл в замене темы сообщения 'Welcome' на 'Подтвердите ваш аккаунт' и тд.

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

appname/app.py

from flask import Flask
from flask.ext.security import Security

from appname.utils import send_mail


app = Flask('appname')
...
security = Security(app, datastore)
app.extensions['security']._send_mail_task = send_mail

appname/utils.py

from flask import current_app
from flask.ext.babel import gettext as _


def send_mail(message):
    if message.subject == 'Welcome':
        message.subject = _('Confirm your account')

    mail = current_app.extensions['mail']
    mail.send(message)

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

UPD. Не только меня волновала эта проблема и посему благодаря фиксам Anthony Plunkett в версии 1.5.1 заголовки сообщений от Flask-Security можно задавать в настройках проекта как:

SECURITY_EMAIL_SUBJECT_REGISTER = 'Confirm your account'

Все доступные настройки описаны в документации.

6 сентября 2012 г.

Flask-Script или улучшенный manage.py для Flask приложений

Наверное, ни один из моих Django-проектов не обходился без пары-тройки кастомных команд, благо эта возможность была одним из столбов архитектуры Django-проекта. Да, написание кода для этих кастомных команд иногда заставляло схватываться за голову и вопрошать: "Why so hard?", но сегодня я не про это.

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

Использовать расширение очень просто и понятно, инициализируем инстанс менеджера, добавляем кастомные команды, запускаем менеджер, если был вызван Python-скрипт. Пример использования, app.py:

from flask import Flask
from flask.ext.script import Manager


app = Flask(__name__)
manager = Manager(app)

@manager.command
def hello():
    """
    Hello, world!
    """
    print('Hello, world!')


if __name__ == '__main__':
    manager.run()
(env)$ python app.py
Please provide a command
  hello      Hello, world!
  runserver  Runs the Flask development server i.e. app.run()
  shell      Runs a Python shell inside Flask application context.

И так как в дефолтной поставке сразу доступны две команды, runserver и shell, мы можем запускать девсервер даже не добавляя строчку app.run() в наш app.py, удобно.

Но описанный подход подходит только для демонстрационных или маленьких приложений, в реальной же жизни мы переносим инициализацию и/или запуск менеджера в давно знакомый нам manage.py:

from flask.ext.script import Manager

from app import app


manager = Manager(app)


@manager.command
def hello():
    """
    Hello, world!
    """
    print('Hello, world!')


if __name__ == '__main__':
    manager.run()

Лирическое отступление. Если честно, я еще точно не определился с тем как более православно объявлять инстанс менеджера и где размещать все кастомные команды. Внутри, хочется объявлять менеджер в app.py, а затем все команды описывать в commands.py, но пока весь код для кастомных команд хранится именно в manage.py, а вот инстанс менеджера таки инициализируется в app.py. Однако почему-то не могу я такой подход порекомендовать всем, так что остановлюсь пока на варианте автора расширения.

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

В остальном у проекта есть отличная документация, так что пользуйтесь, пользуйтесь и еще раз пользуйтесь!

17 мая 2012 г.

Постоянные сессии во Flask'е, один из способов

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

import datetime

from flask import Flask, session


app = Flask(__name__)
app.before_request(lambda: setattr(session, 'permanent', True))
app.permanent_session_lifetime = datetime.timedelta(days=14)

Последняя строчка сниппета выставляет длину сессии в 14 дней, во Flask'е же по дефолту используется 31 день для хранения постоянной сессии. Также эту настройку можно указать как PERMANENT_SESSION_LIFETIME в вашем settings.py.

зы. Однако также не забывайте, что Flask хранит все данные сессии в кукисах, а не как, например, Django только ключ сессии, а все данные уже считывает с базы данных или другого источника. Так что уместно будет использовать flask.session как хранилище каких-то ключей, например, токена текущего залогинненого пользователя.

2 мая 2012 г.

Окончательно дружим Flask и nosetests

Не секрет, что Flask и так хорошо дружит с nosetests, но до сегодняшнего дня был один очень раздражющий момент в их взаимоотношениях :)

Как мы все знаем nosetests по дефолту захватывает все из stdout/stderr и логгинга, чтоб при запуске тестов вывод не засорялся ненужной нам информацией. Однако в дебаг-моде Flask кладет на всех и устанавливает с помощью flask.logging.create_logger функции хэндлер, который начинает срать в консоль при каждом удобном случае, причем минуя все ранее установленные хэндлеры. Итог: куча ненужной логгинг информации при запуске тестов как:

(env)$ TESTING=1 nosetets -c -v -w <package>

Не хорошо, но In mock we trust, так что все что надо - это замокать упомянутую выше функцию в случае, когда мы запускаем тесты в дебаг-моде:

if TESTING and DEBUG:
    from flask import logging as flask_logging

    def mock_create_logger(app):
        return logging.getLogger(app.logger_name)

    flask_logging.create_logger = mock_create_logger

Помещаем этот сниппет в settings.py, затем не забываем загрузить настройки как import settings; app.config.from_object(settings) в нашем app.py - и получаем счастье, nosetests уверенно захватывает все нужное и вывод тестов чист и аккуратен.

Полный гист доступен на Гитхабе, если кто-то готов предложить более красивый вариант решения проблемы - жду в комментариях.

21 апреля 2012 г.

Flask-Dropbox

За что нравится Flask, так это за его концепцию reusable apps. По сравнению с Django на создание по настоящему реюзабельного приложения уходит КУДА меньше времени.

Вот, например, вчера вечером захотелось поиграться с Dropbox API, а сегодня уже готов Flask-Dropbox :) Причем готов с тестовым проектом, который позволит вам загружать файлы в Dropbox, просматривать их и удалять.

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

from flask import Flask
from flask.ext.dropbox import Dropbox, DropboxBlueprint

import settings


app = Flask(__name__)
app.config.from_object(settings)

dropbox = Dropbox(app)
dropbox_blueprint = DropboxBlueprint(dropbox)
app.register_blueprint(dropbox_blueprint, url_prefix='/dropbox')

Единственное на чем следует детально остановится - это настройки. Так как мы имеем дело с API, без них никуда :)

Во-первых, обязательно нужно будет настроить app.secret_key или просто SECRET_KEY, чтобы иметь возможность использовать flask.session (там будут храниться нужные нам токены).

Во-вторых, нужно будет создать какое-то приложение в Dropbox developers site, если еще нет такого и получить там DROPBOX_KEY, DROPBOX_SECRET и DROPBOX_ACCESS_TYPE. Без указания этих значений - кина не будет и Dropbox(app) отдаст вам ValueError :)

После укзания настроек все просто :)

Аутентификация. dropbox.is_authenticated проверит нет ли валидного access token'а в текущей сессии, dropbox.login_url сгенерирует урл для логина при помощи Dropbox, и наконец dropbox.logout_url отдаст урл, переход по которому вылогинит дропбокс пользователя. После успешного логина получить данные о пользователе можно из словаря dropbox.account_info.

Работа с дропбоксом. После того, как пользователь залогинился вся работа с его дропбоксом будет проходить через проперти dropbox.client, который является прокси к инициализированному инстансу DropboxClient. Полный список доступных методов последнего доступен в документации.

В остальном код доступен на ГитХабе, установить можно с PyPI. Пользуйтесь!

3 апреля 2012 г.

Flask-LazyViews

Мне не нравится использовать декоратор @app.route или метод app.add_url_route для регистрации функций отображения во Flask приложениях и блюпринтах, потому что мне намного больше по душе паттерн ленивой загрузки этих функций :)

Именно так и родился Flask-LazyViews. Пример использования тривиальный, для приложений:

from flask import Flask
from flask.ext.lazyviews import LazyViews


app = Flask(__name__)
views = LazyViews(app)

views.add('/', 'views.home')
views.add('/page/', 'views.page')

Или для блюпринтов:

from flask import Blueprint
from flask.ext.lazyviews import LazyViews


blueprint = Blueprint('test', __name__)
views = LazyViews(blueprint, '.views')

views.add('/', 'test')
views.add('/advanced', 'advanced_test', methods=('GET', 'POST'))

Больше информации доступно как всегда на ГитХабе, установить можно с PyPI.

12 марта 2012 г.

Flask-And-Redis

Понадобилось на днях во Flask проекте докрутить поддержку Redis'а. Плюс, хотелось иметь возможность задавать любые настройки в settings модуле, в итоге появился Flask-And-Redis, так как в Flaks-Redis далеко не все можно настроить и оно не Flask-way инициализируется.

Пример использования есть в репозитории, по быстрому повторю и здесь:

from flask import Flask
from flask.ext.redis import Redis


app = Flask(__name__)
redis = Redis(app)

Вуаля :)