Good time of day.
I want to present a project I have been working on lately:
Flask-Admin . In a nutshell, this is an extension for the
Flask framework, which allows you to quickly create an administrative interface in the style of Django.
Architecture
I will try to describe how it all works and what is the difference from the Django admin panel.
The base brick of Flask-Admin is a class that has
view methods. There is a bit of basic code that collects the admin panel and draws the menu. Everything.
')
How does this approach effectively build an administrative interface?
Take, for example, a typical task - CRUD for models.
You can do it in the forehead - write code that accepts a list of models at the entrance, creates forms and labels to display each one, etc. This code will be monolithic, it will work with a specific type of ORM and in general it will be hard to expand.
And you can make a class that can work with one model. Creating an instance of this class and connecting it to the admin area, we get the management interface for this model. Repeat for the rest of the models and the admin is almost ready.
In addition, with this approach, you can easily extend the functionality. Instead of monkey patching, it is enough to redefine the necessary methods and, as a result, we get a new behavior.
This is the main difference from Django - the ability to quickly and painlessly expand or replace the admin functionality for specific tasks.
Flask-admin
What can Flask-Admin, out of the box:
1. Generating a menu (up to two levels) of connected bricks based on access rules
2. The ability to control access, without any assumptions about the authorization system used
3. A set of base classes to create their "bricks"
3. CRUD for
SQLAlchemy models , including paging, sorting, filters, searching, and the like.
4.
File Manager
5. Localization. It works using a modified version of
Flask-Babel , the patch was sent to Armin, but has not yet been accepted. You can temporarily install a version from my repository, it is backward compatible with the current stable from PyPI.
The client side runs on top of
Twitter Bootstrap . The reason is very simple - an adequate appearance and a bunch of UI goodies for quickly creating a UI. Anyway, the admin panel is usually not available to regular users, and writing a UI with bootstrap is still more convenient than without it.
Here is the list of models for
this example :
And this is the built-in file manager:
Closer to the code
And so, in order to connect the admin panel to the application, you need:
1. Create an instance of the class
Admin
2. Add instances of the BaseView class (all the “bricks” are inherited from it)
For example, there are two models: User and Post, you need to create an admin panel. The initialization code will look like this:
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 is an
alchemy session .
ModelView expands in the image and likeness of Django - there is a set of properties at the class / instance level that can be changed.
For example, if you need to exclude the password field in the User model list, do this:
class MyUserAdmin(ModelView): excluded_list_columns = ('password',) admin = Admin(app) admin.add_view(MyUserAdmin(User, db.session))
Nothing prevents changing the properties in the constructor before calling the ancestor:
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'))
If you want, you can add another “view” and a button to the template, when clicked, it will show:
from flask.ext.admin import expose class MyUserAdmin(ModelView):
In order to get a “normal” look and feel, in templates you need to inherit from 'admin / master.html':
{% extends 'admin/master.html' %} {% block body %} Hello World from MyView! {% endblock %}
The behavior of the templates and view methods is completely analogous to the standard one from Flask.
Expansion of functionality
The extension of the functional can be divided into two parts:
1. Changing the behavior of the built-in "batteries"
2. Writing something new
Batteries
Architecturally, scaffolding models consist of two layers:
1. The level of access to data. Here is the logic of interaction with a specific implementation of ORM - from model introspection to data access methods
2. Level UI and the rest of logic
Combining both levels (through inheritance), we get a ready-made "battery" for a particular ORM. We need to support, say, mongo-alchemy - we write logic, inherit from the base class, we get CRUD for mongo.
ModelView is able to configure itself through the properties of a class (or an instance, if it is prescribed in the constructor). However, if there are not enough ready-made settings, you can always inherit, override the necessary methods and get a completely different behavior.
Similarly, the file manager works. For example, if you want to deny access to the reports directory for a Mike user, you can do something like this:
class MyFileAdmin(FileAdmin): def is_accessible_path(self, path): if path.startswith('reports'): return user.login != 'mike' return True
New functionality
Now about adding a completely new functionality. This is how a new “brick” is added:
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'))
An item will appear in the menu and when opening the 'Hello' item, the index view will be called. Looks like that:
To generate links between views, you can use the usual url_for with a dot at the beginning of the view name:
from flask import url_for class MyView(BaseView): @expose('/') def index(self): url = url_for('.help') return self.render('myproject/admin/index.html', url=url) @expose('/help/') def help(self): return self.render('myproject/admin/help.html', id=id)
Further development is no different from writing normal code under Flask.
Total
Currently, the library's API has more or less stabilized and is being successfully used in several projects.
Examples are here:
github.com/mrjoes/flask-admin/tree/master/examples
Documentation here:
flask-admin.readthedocs.org/en/latest
And, as usual, patches are always welcome.