- PVSM.RU - https://www.pvsm.ru -
Доброе время суток.
Хочу представить проект, над которым работал в последнее время: Flask-Admin [1]. Если в двух словах, это расширение для фреймворка Flask [2], которое позволяет быстро создавать административный интерфейс в стиле Django.
Попробую описать как это все работает и в чем отличие от админки Django.
Базовый кирпичик Flask-Admin это класс у которого есть view [3] методы. Есть немного базового кода, который собирает из кирпичиков админку и рисует меню. Все.
Как такой подход позволяет эффективно строить административный интерфейс?
Возьмем, к примеру, типовую задачу — CRUD для моделей.
Можно сделать «в лоб» — написать код, который примет на входе список моделей, создаст формы и таблички для отображения каждой и т.д. Данный код будет монолитным, будет работать с конкретным типом ORM и вообще его будет тяжело расширять.
А можно сделать класс, который умеет работать с одной моделью. Создав экземпляр такого класса и подключив его в админку, получим интерфейс управления этой моделью. Повторяем для остальных моделей и админка почти готова.
Кроме того, при таком подходе можно легко расширять функционал. Вместо monkey patching'а, достаточно переопределить нужные методы и, в результате, получаем новое поведение.
Это и есть основное отличие от Django — возможность быстро и безболезненно расширить или заменить функционал админки под конкретные задачи.
Что умеет Flask-Admin, из коробки:
1. Генерацию меню (до двух уровней) из подключенных кирпичиков с учетом правил доступа
2. Возможность управления доступом, без каких либо предположений о используемой системе авторизации
3. Набор базовых классов для создания своих «кирпичиков»
3. CRUD для моделей SQLAlchemy [4], включая пейджинг, сортировку, фильтры, поиск и тому подобное.
4. Файловый менеджер [5]
5. Локализация. Работает с помощью модифицированной версии Flask-Babel [6], патч отправлен Армину, но до сих пор не принят. Временно можно установить версию из моего репозитория, она обратно-совместима с текущим stable из PyPI.
Клиентская часть работает поверх Twitter Bootstrap [7]. Причина очень простая — адекватный внешний вид и куча UI вкусностей для быстрого создания UI. Так или иначе, админка обычно недоступна обычным пользователей, а писать UI с bootstrap все же удобнее, чем без него.
Вот так выглядит список моделей для этого примера [8]:

А вот так — встроенный файловый менеджер:

И так, для того что бы подключить админку к приложению, нужно:
1. Создать экземпляр класса Admin [9]
2. Добавить экземпляров класса BaseView (все «кирпичики» наследуются от него)
Например, есть две модели: User и Post, нужно создать админку. Код инициализации будет выглядеть так:
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqlamodel import ModelView
admin = Admin(app)
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Post, db.session))
db.session это сессия алхимии [10].
ModelView расширяется по образу и подобию Django — есть набор свойств на уровне класса/экземпляра, которые можно менять.
Например, если в списке моделей User нужно исключить поле password, делаем так:
class MyUserAdmin(ModelView):
excluded_list_columns = ('password',)
admin = Admin(app)
admin.add_view(MyUserAdmin(User, db.session))
Ничто не мешает менять свойства в конструкторе до вызова предка:
class MyUserAdmin(ModelView):
def __init__(self, session, name, excluded=None):
if excluded:
self.excluded_list_columns = excluded
super(MyUserAdmin, self).__init__(User, session, name=name)
admin = Admin(app)
admin.add_view(MyUserAdmin(db.session, 'View1', ('password',))
admin.add_view(MyUserAdmin(db.session, 'View2', ('email','password'))
Если хочется, можно добавить еще одну «вьюшку» и кнопку в шаблон, при нажатии на которую будет показывается новая вьюшка. Код будет такой:
from flask.ext.admin import expose
class MyUserAdmin(ModelView):
# Кнопка будет в шаблоне
list_template = 'myproject/admin/userlist.html'
@expose('/report/<int:id>/')
def report(self, id):
# Логика тут
return self.render('myproject/admin/userreport.html', id=id)
def __init__(self, session):
super(MyUserAdmin, self).__init__(User, session)
admin = Admin(app)
admin.add_view(MyUserAdmin(db.session))
Для того, что бы получить нормальный look and feel, в шаблонах нужно унаследоваться от 'admin/master.html':
{% extends 'admin/master.html' %}
{% block body %}
Hello World from MyView!
{% endblock %}
Поведение шаблонов и view методов полностью аналогично стандартным из Flask'а.
Расширение функционала можно разделить на две части:
1. Изменение поведения встроенных «батареек»
2. Написание чего-то нового
Архитектурно, scaffolding моделей состоит из двух слоев:
1. Уровень доступа к данным. Тут находится логика взаимодействия с конкретной реализацией ORM — от интроспекции модели до методов доступа к данным
2. Уровень UI и остальной логики
Комбинируя оба уровня (через наследование), получаем готовую «батарейку» для конкретной ORM. Нужно поддержать, скажем, mongo-alchemy — пишем логику, наследуемся от базового класса, получаем CRUD для mongo.
ModelView умеет конфигурировать себя через свойства класса (или экземпляра, если прописали в конструкторе). Однако, если готовых возможностей настройки не хватает — всегда можно унаследоваться, переопределить нужные методы и получить совершенно другое поведение.
Аналогично работает файловый менеджер. Например, если нужно запретить доступ к директории reports для пользователя Mike, сделать можно как-то так:
class MyFileAdmin(FileAdmin):
def is_accessible_path(self, path):
if path.startswith('reports'):
return user.login != 'mike'
return True
Теперь о добавлении совершенно нового функционала. Вот так добавляется новый «кирпичик»:
from flask.ext.admin import Admin, BaseView, expose
class MyView(BaseView):
@expose('/')
def index(self):
return self.render('myproject/admin/index.html')
admin = Admin(app)
admin.add_view(MyView(name='Hello'))
В меню появится пункт и при открытии пункта 'Hello' вызовется вьюшка index. Выглядит так:

Для генерации ссылок между вьюшками, можно использовать обычный url_for с точкой в начале имени вьюшки:
from flask import url_for
class MyView(BaseView):
@expose('/')
def index(self):
url = url_for('.edit')
return self.render('myproject/admin/index.html', url=url)
@expose('/edit/<int:id>/')
def edit(self, id):
return self.render('myproject/admin/edit.html', id=id)
Дальше разработка ничем не отличается от написания обычного кода под Flask.
На текущий момент API библиотеки более-менее стабилизировалось и успешно используется в нескольких проектах.
Примеры лежат тут: github.com/mrjoes/flask-admin/tree/master/examples [11]
Документация тут: flask-admin.readthedocs.org/en/latest/ [12]
И, как обычно, патчи всегда приветствуются.
Автор: Joes
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/12325
Ссылки в тексте:
[1] Flask-Admin: https://github.com/mrjoes/flask-admin
[2] Flask: http://flask.pocoo.org/
[3] view: http://flask.pocoo.org/docs/tutorial/views/
[4] моделей SQLAlchemy: http://flask-admin.readthedocs.org/en/latest/quickstart/#model-views
[5] Файловый менеджер: http://flask-admin.readthedocs.org/en/latest/quickstart/#file-admin
[6] Flask-Babel: https://github.com/mrjoes/flask-babel
[7] Twitter Bootstrap: http://twitter.github.com/bootstrap/
[8] этого примера: https://github.com/mrjoes/flask-admin/tree/master/examples/sqla
[9] Admin: http://flask-admin.readthedocs.org/en/latest/api/mod_base/#admin
[10] сессия алхимии: http://docs.sqlalchemy.org/en/rel_0_5/session.html
[11] github.com/mrjoes/flask-admin/tree/master/examples: https://github.com/mrjoes/flask-admin/tree/master/examples
[12] flask-admin.readthedocs.org/en/latest/: http://flask-admin.readthedocs.org/en/latest/
Нажмите здесь для печати.