Usage

Administration interface for Invenio applications.

Invenio-Admin is an optional component of Invenio, responsible for registering and customizing the administration panel for model views and user-defined admin pages. The module uses standard Flask-Admin features and assumes very little about other components installed within a given Invenio instance.

Quick start

This section presents a minimal working example of the Invenio-Admin.

First, let us create a new Flask application:

>>> from flask import Flask
>>> app = Flask('DinerApp')

and load the Invenio-DB and Invenio-Admin extensions:

>>> from invenio_db import InvenioDB
>>> from invenio_admin import InvenioAdmin
>>> ext_db = InvenioDB(app)
>>> ext_admin = InvenioAdmin(app, view_class_factory=lambda x: x)

Warning

We use the view_class_factory parameter above to disable the authentication to the admin panel, in order to simplify this tutorial. Do not use this for production systems, as you will grant access to the admin panel to anonymous users!

In full application with an authentication system in place, it is sufficient to instantiate the extension like:

ext_admin = InvenioAdmin(app)

Let’s now define a simple model with a model view, and one base view:

>>> from invenio_db import db
>>> from flask_admin.contrib.sqla import ModelView
>>> from flask_admin.base import BaseView, expose
>>> class Lunch(db.Model):
...     __tablename__ = 'diner_lunch'
...     id = db.Column(db.Integer, primary_key=True)
...     meal_name = db.Column(db.String(255), nullable=False)
...     is_vegetarian = db.Column(db.Boolean(name='is_v'), default=False)
...
>>> class LunchModelView(ModelView):
...     can_create = True
...     can_edit = True
...
>>> class MenuCard(BaseView):
...     @expose('/')
...     def index(self):
...         return "HelloMenuCard!"

and register them in the admin extension:

>>> ext_admin.register_view(LunchModelView, Lunch, db.session)
>>> ext_admin.register_view(MenuCard)

Finally, initialize the database and run the development server:

>>> from sqlalchemy_utils.functions import create_database
>>> app.config.update(SQLALCHEMY_DATABASE_URI='sqlite:///test.db',
...     SECRET_KEY='SECRET')
...
>>> with app.app_context():
...     create_database(db.engine.url)
...     db.create_all()
>>> app.run() 

You should now be able to access the admin panel http://localhost:5000/admin.

Adding admin views from Invenio module

In real-world scenarios you will most likley want to add an admin view for your custom models from within the Invenio module or an Invenio overlay application. Instead of registering it directly on the application as in the example above, you can use entry points to register those automatically.

Defining admin views

Let us start with defining the admin.py file inside your module or overlay, which will contain all admin-related classes and functions. For example, assuming a Invenio-Diner module, the file could reside in:

invenio-diner/invenio_diner/admin.py.

In this example we will define two model views for two database models and one separate base view for statistics page. The content of the file is as follows:

# invenio-diner/invenio_diner/admin.py
from flask_admin.base import BaseView, expose
from flask_admin.contrib.sqla import ModelView
from invenio_db import db
from .models import Snack, Breakfast

class SnackModelView(ModelView):
    can_create = True
    can_edit = True
    can_view_details = True
    column_list = ('id', 'name', 'price', )

class BreakfastModelView(ModelView):
    can_create = False
    can_edit = False
    can_view_details = True
    column_searchable_list = ('id', 'toast', 'eggs', 'bacon' )

class DinerStats(BaseView):
    @expose('/')
    def index(self):
        return "Welcome to the Invenio-Diner statistics page!"

    @expose('/sales/')
    def sales(self):
        return "You have served 0 meals!"

snack_adminview = {
    'view_class': Snack,
    'args': [SnackModelView, db.session],
    'kwargs': {'category': 'Diner'},
}

breakfast_adminview = {
    'view_class': Breakfast,
    'args': [BreakfastModelView, db.session],
    'kwargs': {'category': 'Diner'},
}

stats_adminview = {
    'view_class': DinerStats,
    'kwargs': {'name': 'Invenio Diner Stats'},
}

__all__ = (
    'snack_adminview',
    'breakfast_adminview',
    'stats_adminview',
)

Note

You have to define a dictionary for each BaseView and Model-ModelView pairs (see stats_adminview, snack_adminview and breakfast_adminview above) in order to have the admin views automatically registered via entry points (see next section).

The args and kwargs keys in the dictionaries are passed to the constructor of the view class once it is intialized.

Registering the entry point

The default way of adding admin views to the admin panel is though setuptools’ entry point discovery. To do that, a newly created module has to register an entry point under the group invenio_admin.views inside its setup.py as follows:

# invenio-diner/setup.py
setup(
  entry_points={
    'invenio_admin.views': [
      'invenio_diner_snack = invenio_diner.admin.snack_adminview',
      'invenio_diner_breakfast = invenio_diner.admin.breakfast_adminview',
      'invenio_diner_stats = invenio_diner.admin.stats_adminview',
    ],
  },
)

Authentication and authorization

By default Invenio-Admin protects the admin views from unauthenticated users with Flask-Login and restricts the access on a per-permission basis using Flask-Security. In order to login to a Invenio-Admin panel the user needs to be authenticated using Flask-Login and have a Flask-Security identity which provides the ActionNeed('admin-access').

Note

If you want to use a custom permission rule, you can easily specify your own permission factory in the configuration variable invenio_admin.config.ADMIN_PERMISSION_FACTORY.

For more information, see the default factory: invenio_admin.permissions.admin_permission_factory() and how the the view is using it: invenio_admin.views.protected_adminview_factory()

Styling

At core, Invenio-Admin uses Flask-Admin for rendering the admin panel and all of its views. All of the features for defining the ModelViews and BaseViews can be found in the official Flask-Admin documentation. Nonetheless, we will mention some of the ones that were already made easy to use directly in Invenio-Admin.

Custom database type filters

Non-basic data types can be made easier to search for and filter using type filters. This way, fields of certain type that is not searchable by default can be extended with that functionality. For example see a built-in UUID filter invenio_admin.filters.UUIDEqualFilter. You can enable the custom fields filters, by setting a variable filter_converter on the ModelView class. See an example of a custom filter converter in invenio_admin.filters.FilterConverter.

Assuming that the id field in Snack model from the example above is a UUID-type field, you could enable the UUID filtering on this model as follows:

from invenio_admin.filters import FilterConverter

class SnackModelView(ModelView):
    filter_converter = FilterConverter()  # Add filter converter
    can_create = True
    can_edit = True
    can_view_details = True
    column_list = ('id', 'name', 'price', )

Base template

Styling of the administration interface can be changed via the configuration variable ADMIN_BASE_TEMPLATE.

If Invenio-Theme is installed, ADMIN_BASE_TEMPLATE is automatically set to use the AdminLTE theme which provides an extra configuration variable ADMIN_UI_SKIN which controls the AdminLTE skin (e.g. skin-blue or skin-black). See AdminLTE documentation for details on supported skins.

If Invenio-Theme is not installed the default Flask-Admin templates will be used (based on Bootstrap).

View template mode

Flask-Admin view templates (forms etc.) can either use Bootstap 2 or 3. By default the template mode is set to Bootstrap 3 but can be controlled through ADMIN_TEMPLATE_MODE configuration variable.