A common pattern in application design is to apply CRUD to your Model, and then provide a Graphical User Interface for people to interact with the Model. Flask-Admin makes it very easy to create a basic interface with Create-Read-Update-Delete functionality, and provides a framework for designing much more sophisticated interfaces.
This document discusses a simple CRUD with Flask-Admin, and then extends the CRUD with additional functionality.
When Flask-Admin creates a GUI, it automatically discovers the Model Attributes and creates a web form containing fields for all the attributes. Flask-Admin provides the BaseModelView class as the foundation for building Views that a user can interact with to inspect and control a Model. Flask-Diamond provides AdminModelView, which applies an authentication requirement so that only users with the Admin role can access the View.
The following example imports a class called Planet (which is described in the Model documentation). Then, the Planet class is added to the GUI using the add_view() method.
from flask_diamond import Diamond
from flask_diamond.administration import AdminModelView
from .models import User, Role, Planet
class my_diamond_app(Diamond):
def init_administration(self):
admin = self.super("administration", user=User, role=Role)
admin.add_view(AdminModelView(
Planet,
db.session,
name="Planet",
category="Admin")
)
When the server is launched, it provides a GUI facility for applying CRUD operations to the Planet model. Due to the use of AdminModelView, the application will now require a password before allowing anybody to create, read, update, or delete any Planet object.
The category parameter causes the GUI to put this View into the menu bar beneath the heading “ModelAdmin”. The name parameter indicates this link will be titled Planet. Now you can find the Planet CRUD by navigating through the menu to Models and then to Planet.
BaseModelView actually creates multiple views that provide CRUD functionality:
Create-List-Edit-Delete corresponds directly to Create-Read-Update-Delete.
Flask-Admin makes it pretty easy to add custom functionality through Python class inheritance [1]. In the Model documentation, the Planet Model provides a bombard() method that sends an asteroid at a planet. The following sections demonstrate how to expose the bombard() method and create a user interface widget for calling that method.
In addition to the basic CRUD views, new views can be created for doing other things with Models. Since the Planet class has been extended with a bombard() method, let’s create a URL endpoint to send an asteroid at a planet.
from flask_diamond import Diamond
from flask_diamond.administration import AdminModelView
from flask_admin import expose
from .models import User, Role, Planet
class PlanetModelView(AdminModelView):
@expose('/bombard/<planet_id>')
def bombard(self, planet_id):
the_planet = models.Planet.get(planet_id)
the_planet.bombard(mass=10.0)
return flask.redirect(flask.url_for('.list_view'))
class my_diamond_app(Diamond):
def init_administration(self):
admin = self.super("administration", user=User, role=Role)
admin.add_view(PlanetModelView(
models.Planet,
db.session,
name="Planet",
category="Admin")
)
One simple way to add functionality to the user interface is to use Flask-Admin’s formatters to make a field into an interactive widget. This basic pattern is demonstrated by formatting Planet.mass with a “bombard” button:
import jinja2
from flask_diamond import Diamond
from flask_diamond.administration import AdminModelView
from flask_admin import expose
from .models import User, Role, Planet
class PlanetModelView(AdminModelView):
def mass_formatter(self, context, model, name):
mass_widget_template = "{0} <a href='{1}'>bombard!</a>"
mass_widget = mass_widget_template.format(
model.age,
flask.url_for(".bombard", planet_id=model.id)
)
return jinja2.Markup(mass_widget)
column_formatters = {
"age": mass_formatter,
}
When these two PlanetModelView examples are combined, the result is a user interface that can bombard a planet with asteroids when clicked.
The following AuthModelView includes examples for overriding various fields within the model view. The full documentation for ModelView should be consulted for more information, but this example is intended to describe how that information may be applied within a Flask-Diamond project.
class PlanetAdmin(AuthModelView):
edit_template = 'planet_edit.html'
column_list = ("name", "mass")
form_overrides = {
"upload_buffer": FileUploadField
}
form_args = {
'upload_buffer': {
'label': 'Planet PDF',
'base_path': "/tmp",
}
}
Flask-Admin is really powerful, and the best way to learn more is by reading the Flask-Admin documentation.
Footnotes
[1] | Incidentally, Python class inheritance is the same mechanism used by Flask-Diamond for customization. Inheritance is discussed further in writing_an_application_with_flask-diamond. |