Not Logged In

django-dash 0.4.13

django-dash (later on named Dash) is a customisable, modular dashboard
application framework for Django.

Dash allows users to create their own custom dashboards. Supports theming (in
Dash themes are called layouts) and multiple workspaces. Dash comes with
extensive pythonic API which allows developers to create new Dash plugins, as
well as to modify bundled ones.

To make a clearer association, think of Android for tablets (shortcuts, widgets
and apps) or Windows 8 for tablets or desktops.

Dash inherits all those concepts and makes it possible to implement a dashboard
system for Django applications with minimal efforts.

Prerequisites

Django 1.5, 1.6, 1.7

Python 2.6.8+, 2.7.*, 3.3.*

Note, that Django 1.7 is not yet proclaimed to be flawlessly supported!

Key concepts

Each layout (theme) consist of placeholders. Each plugin widget has its’ own
specific HTML/JavaScript/CSS.

There might be multiple themes implemented and installed, but only one can
be active for a certain user. Default layout is chosen system wide, but each
user (if has an appropriate permission) can choose his preferred layout.

Placeholder is a space, in which the plugin widgets are placed.

Placeholders are rectangles consisting of cells. Each placeholder has its’
own custom number of rows and columns.

Workspace is just another named dashboard. Users switch between workspaces
in navigation. Amount of workspaces is unlimited.

Plugin is a (Django) micro app. Most heavy work should happen in plugin.
Plugin may have its’ own views, urls, etc. Rendering happens with use of
plugin widgets.

Plugin widgets are mainly responsible for rendering of the plugin data.
Each plugin widget has its’ own specific HTML/JavaScript/CSS. A single
plugin widget is registered for a triple (layout, placeholder, plugin).

Public dashboard (implemented as a contrib app, which makes it optional)
allows users to make their workspaces public. If user chooses to make his
dashboard public, default workspace becomes public. As for non-default
workspaces, user can still make each of them private or public.

Main features

Customisable layouts (aka theeming).

Multiple workspaces.

Tunable access permissions to plugins.

Public dashboards (as a contrib app).

Clonable workspaces. It’s possible to clone entire workspace, including
all the plugins into another workspace.

Copy/paste functionality for plugin widgets.

FAQ

Question: Is it possible to have Dash working with a (pick what’s applicable:
D3, Polychart2, or some other library for making charts).

Some screenshots

Demo

Live demo

See the public dashboard of a test_demo_user to get an idea of what
it could become.

Run demo locally

In order to be able to quickly evaluate the django-dash, a demo app (with a
quick installer) has been created (works on Ubuntu/Debian, may work on other
Linux systems as well, although not guaranteed). Follow the instructions
below for having the demo running within a minute.

If quick installer doesn’t work for you, see the manual steps on running the
example project.

Take a look at the templates in “example/example/templates” directory for
getting a better idea of how to transform your own- or thirdy-part- templates
into Dash templates.

Also, the example project
has example layouts, plugins and widgets implemented. Take it as a good example
of how to add widgets for existing plugins to your own customly made layout.
Make sure to see how same is done for the bundled layouts.

Layout and placeholder classes should be placed in the dash_layouts.py file.

Each layout should be put into the INSTALLED_APPS of your Django projects’
settings.py module.

INSTALLED_APPS=(# ...'path.to.layout.example',# ...)

path/to/layout/example/dash_layouts.py

Step by step review of a how to create and register a layout and placeholders.
Note, that Dash autodiscovers your layouts by name of the file
dash_layouts.py. The module, in which the layouts are defined, has to be
named dash_layouts.py.

classExampleMainPlaceholder(BaseDashboardPlaceholder):uid='main'# Unique ID of the placeholder.cols=6# Number of columns in the placeholder.rows=5# Number of rows in the placeholder.cell_width=150# Width of a single cell in the placeholder.cell_height=110# Height of a single cell in the placeholder.

Defining the Shortcuts placeholder.

classExampleShortcutsPlaceholder(BaseDashboardPlaceholder):uid='shortcuts'# UID of the placeholder.cols=1# Number of columns in the placeholder.rows=10# Number of rows in the placeholder.cell_width=60# Width of a single cell in the placeholder.cell_height=55# Height of a single cell in the placeholder.

Defining and registering the Layout.

classExampleLayout(BaseDashboardLayout):uid='example'# Layout UID.name='Example'# Layout name.# View template. Master template used in view mode.view_template_name='example/view_layout.html'# Edit template. Master template used in edit mode.edit_template_name='example/edit_layout.html'# All placeholders listed. Note, that placeholders are rendered in the# order specified here.placeholders=[ExampleMainPlaceholder,ExampleShortcutsPlaceholder]# Cell units used in the entire layout. Allowed values are: 'px', 'pt',# 'em' or '%'. In the ``ExampleMainPlaceholder`` cell_width is set to 150.# It means that in this particular case its' actual width would be `150px`.cell_units='px'# Layout specific CSS.media_css=('css/dash_layout_example.css',)# Layout specific JS.media_js=('js/dash_layout_example.js',)# Registering the layout.layout_registry.register(ExampleLayout)

HTML templates

You custom layout should be interited from base layout templates (view or
edit). Both view and edit layouts share a lot of things, still edit layout is
a bit more “heavy”.

view_layout.html should inherit from “dash/layouts/base_view_layout.html”.

edit_layout.html should inherit from “dash/layouts/base_edit_layout.html”.

Both “dash/layouts/base_view_layout.html” and
“dash/layouts/base_edit_layout.html” inherit from
“dash/layouts/base_layout.html”, which in its’ turn inherits from
“dash/base.html”.

Note, that when rendered to HTML, each Dash template, gets a body class
“layout” + layouts’ unique identifier (UID). So, the ExampleLayout
layout would automatically get the class “layout-example”.

<bodyclass="layout-example">

In case of Android layout (UID “android”) it would be as follows.

<bodyclass="layout-android">

Base your layout specific custom CSS on presence of those classes.

Same goes for Placeholders. Each placeholder gets id_ + placeholders’ UID and
the classes “placeholder” and “placeholder-” + placeholders’ UID. So, the
ExampleMainPlaceholder would look as follows.

<divid="id_main"class="placeholder placeholder-main">

And the ExampleShortcutsPlaceholder placeholder would look as follows.

<divid="id_shortcuts"class="placeholder placeholder-shortcuts">

Same goes for plugin widgets. Apart from some other classes that each plugin
widget would get for positioning, it gets the “plugin” and “plugin-” + plugin
UID. See the following example (for the plugin Dummy with UID “dummy”). Each
plugin also gets an automatic UID on the moment when rendered. In the example
below it’s the “p6d06f17d-e142-4f45-b9c1-893c38fc2b01”.

In some cases, you would need plugin specific overridable settings (see
dash.contrib.plugins.weather plugin as an example. You are advised to
write your settings in such a way, that variables of your Django projects’
settings.py module would have DASH_PLUGIN_ prefix.

path/to/plugin/sample_memo/dash_plugins.py

Step by step review of a how to create and register a plugin and plugin
widgets. Note, that Dash autodiscovers your plugins if you place them into a
file named dash_plugins.py of any Django app listed in INSTALLED_APPS
of your Django projects’ settings module.

Define and register the plugin

As already stated, a single plugin widget is registered for a triple (layout,
placeholder, plugin). That means, that if you need two widgets, one sized 1x1
and another sized 2x2, you need two plugins for it. You can either manually
define all plugins and widgets for the sizes desired, or define a single
base plugin or a widget class and have it factory registered for a number of
given sizes. Below, both approaches would be explained.

Repeat the steps below for each plugin size (or read about factory registering
the plugins and widgets below).

Factory register plugins

Alternatively, you can define just a single plugin base class and have it
factory registered for the given sizes. The code below would produce and
register classes for in sizes 1x1 and 2x2. When you need to register a plgin
for 10 sizes, this approach clearly wins. Besides, it’s very easy to get a
clear overview of all plugins sizes registered.

path/to/plugin/sample_memo/dash_widgets.py

Why to have another file for defining widgets? Just to keep the code clean and
less messy, although you could perfectly define all your plugin widgets in the
module dash_plugins.py, it’s recommended to keep it separate.

Take into consideration, that dash_widgets.py is not an autodiscovered file
pattern. All your plugin widgets should be registered in modules named
dash_plugins.py.

Define and register the plugin widget

classSampleMemo2x2ExampleMainWidget(BaseDashboardPluginWidget):layout_uid='example'# Layout for which the widget is writtenplaceholder_uid='main'# Placeholder within the layout for which# the widget is writtenplugin_uid='sample_memo_2x2'# Plugin for which the widget is writtencols=2# Number of widget columnsrows=2# Number of widget rowsdefrender(self,request=None):context={'plugin':self.plugin}returnrender_to_string('sample_memo/render_main.html',context)

Memo plugin widget for Example layout (placeholder shortcuts).

classSampleMemo1x1ExampleShortcutWidget(SampleMemo2x2ExampleMainWidget):placeholder_uid='shortcuts'# Placeholder within the layout for which# the widget is writtencols=1# Number of widget columnsrows=1# Number of widget rowsdefrender(self,request=None):context={'plugin':self.plugin}returnrender_to_string('sample_memo/render_shortcuts.html',context)

Factory register plugin widgets

Alternatively, you can define just a single plugin widget base class and have
it factory registered for the given sizes. The code below would produce and
register classes for in sizes 1x1 and 2x2.

“sample_memo” is the base name of the plugin and it should match the name
given to plugin factory exactly.

“example” is the uid of the layout, for which the widget is being registered.

“main” is the uid of the placeholder, for which the widget it being
registered.

path/to/plugin/sample_memo/forms.py

What are the plugin forms? Very simple - if plugin is configurable, it has a
form. If you need to have a custom CSS or a JavaScript included when rendering
a speicifc form, use Django’s class Media directive in the form.

Note, that you have to be logged in, in order to use the dashboard. If your new
plugin doesn’t appear, set the DASH_DEBUG to True in your Django’s local
settings module (local_settings.py), re-run your code and check console for
error notifications.

Plugin and widget factory

In general, when making a new plugin, base widgets are made for then too. By
creating base widgets you avoid duplication of the code. See the example below.

The code above will generate “memo_5x6”, “memo_6x5” and “memo_6x6” plugin
classes which subclass the BaseMemoPlugin and register them in the plugin
registry. The uid property would be automatically generated.

The code above will generate “memo_5x6”, “memo_6x5” and “memo_6x6” plugin
widget classes which subclass the BaseMemoWidget and register them in the
plugin widget registry. The layout_uid, placeholder_uid,
plugin_uid, cols and rows properties would be automatically
generated.

Of course, there would be cases when you can’t use factory, for example because
each of your plugins or widgets differs from others by tiny important bits, but
if you notice yourself subclassing the base widget or plugin many times without
any change to the code, then it’s perhaps a right time to start using the
factory.

Layout, plugin and widget summary

When making your own layouts, plugins and plugin widgets you are free to use
the API as you wish. While developing the Dash, I found the follow practices
useful:

When making a new plugin, always make a base plugin class, from which all
size specific ones would derrive.

Do create base plugin widgets (with HTML templates) in the plugin, but do not
register them there. Use factory (dash.factory) to generate and register
layout specific plugin widgets - preferrably in the layout module.

If you’re adding custom plugin to existing bundled layout (those that
reside in dash.contrib.layouts), create a new module named
dash_custom (or any other name that you preffer) and factory
generate/register your layout specific plugin widgets in a module named
dash_plugins.py (do not forget to add the module to INSTALLED_APPS, so
that it autodiscovered).

Permissions

Plugin system allows administrators to specify the access rights to every
plugin. Dash permissions are based on Django Users and User Groups. Access
rights are managable via Django admin (/administration/dash/dashboardplugin/).
Note, that your admin URL prefix may vary from the one given in example (it’s
usually “/admin/”, while in example it’s “/administration/”). If user doesn’t
have the rights to access plugin, it doesn’t appear on his dashboard even if
has been added to it (imagine, you have once granted the right to use the news
plugin to all users, but later on decided to limit it to Staff members group
only). Note, that superusers have access to all plugins.

Management commands

dash_find_broken_dashboard_entries. Find broken dashboard entries that
occur when some plugin which did exist in the system, no longer exists.

dash_sync_plugins. Should be ran each time a new plugin is being added
to the Dash.

dash_update_plugin_data. A mechanism to update existing plugin data in
case if it had become invalid after a change in a plugin. In order for it
to work, each plugin should implement and update method, in which the
data update happens.

Tuning

There are number of Dash settings you can override in the settings.py module
of your Django project:

DASH_RESTRICT_PLUGIN_ACCESS (bool): If set to True, (Django) permission
system for dash plugins is enabled. Defaults to True. Setting this to False
makes all plugins available for all users.

DASH_DISPLAY_AUTH_LINK (bool): If set to True, the log out link is shown
in the Dash drop-down menu. Defaults to True.

For tuning of specific contrib plugin, see the docs in the plugin directory.

Styling tips

Font Awesome is used for icons. As a convension, all icons of font-awesome are
placed within a span. Next to their original class, they all should be getting
an extra class “iconic”. Follow that rule when making a new layout or a
plugin (HTML). It allows to make the styling easy, since icon colours could be
then changed within no time.

Bundled plugins and layouts

Dash ships with number of bundled (demo) plugins and layouts that are mainly
made to demonstrate its’ abilities. In order to work amoung various layouts
(themes), each plugin has a single widget registered for a single layout.
It’s possible to unregister a bundled widget and replace it with a custom one.

Bundled plugins

Below a short overview of the plugins. See the README.rst file in directory
of each plugin for details.

Dummy plugin.
Mainly made for quick testing. Still, is perfect example of how to write a
plugin and widgets.

Image plugin.
Allows users to put images on their dashboard. If you plan to make a plugin
that deals with file uploads, make sure to check the source of this one
first.