greatly improved documentation, better customization API

This commit is contained in:
David Jean Louis 2010-02-08 13:26:07 +01:00
parent a1807c20e2
commit 4feb222628
29 changed files with 1129 additions and 379 deletions

View File

@ -0,0 +1,62 @@
"""
Dashboard registry.
"""
from admin_tools.dashboard.models import Dashboard
class Registry(object):
"""
Registry for application dashboards.
"""
registry = {}
def register(cls, klass, app_name):
if not issubclass(klass, Dashboard):
raise ValueError('%s is not an instance of Dashboard' % klass)
if app_name in cls.registry:
raise ValueError('A dashboard has already been registered for '
'the application "%s"', app_name)
cls.registry[app_name] = klass
register = classmethod(register)
def register(cls, *args, **kwargs):
"""
Register a custom dashboard into the global registry.
"""
Registry.register(cls, *args, **kwargs)
def autodiscover(blacklist=[]):
"""
Automagically discover custom dashboards and menus for installed apps.
Optionally you can pass a ``blacklist`` of apps that you don't want to
provide their own app index dashboard.
"""
import imp
from django.conf import settings
from django.utils.importlib import import_module
blacklist.append('admin_tools.dashboard')
blacklist.append('admin_tools.menu')
blacklist.append('admin_tools.theming')
for app in settings.INSTALLED_APPS:
# skip blacklisted apps
if app in blacklist:
continue
# try to import the app
try:
app_path = import_module(app).__path__
except AttributeError:
continue
# try to find a app.dashboard module
try:
imp.find_module('dashboard', app_path)
except ImportError:
continue
# looks like we found it so import it !
import_module('%s.dashboard' % app)

View File

@ -1,111 +0,0 @@
"""
django-admin-tools default dashboards.
"""
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from admin_tools.dashboard.models import *
class DefaultIndexDashboard(Dashboard):
"""
Default admin index dashboard.
"""
def __init__(self, *args, **kwargs):
super(DefaultIndexDashboard, self).__init__(*args, **kwargs)
# append a link list module for "quick links"
self.append(LinkListDashboardModule(
title=_('Quick links'),
layout='inline',
draggable=False,
deletable=False,
collapsible=False,
entries=[
{
'title': _('Return to site'),
'url': '/',
},
{
'title': _('Change password'),
'url': reverse('admin:password_change'),
},
{
'title': _('Log out'),
'url': reverse('admin:logout')
},
]
))
# append an app list module for "Applications"
self.append(AppListDashboardModule(
title=_('Applications'),
exclude_list=('django.contrib',),
))
# append an app list module for "Administration"
self.append(AppListDashboardModule(
title=_('Administration'),
include_list=('django.contrib',),
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
enabled=False,
title=_('Recent Actions'),
limit=5
))
# append a feed module
self.append(FeedDashboardModule(
enabled=False,
title=_('Latest Django News'),
feed_url='http://www.djangoproject.com/rss/weblog/',
limit=5
))
# append another link list module for "support".
self.append(LinkListDashboardModule(
title=_('Support'),
entries=[
{
'title': _('Django documentation'),
'url': 'http://docs.djangoproject.com/',
'external': True,
},
{
'title': _('Django "django-users" mailing list'),
'url': 'http://groups.google.com/group/django-users',
'external': True,
},
{
'title': _('Django irc channel'),
'url': 'irc://irc.freenode.net/django',
'external': True,
},
]
))
class DefaultAppIndexDashboard(AppIndexDashboard):
"""
Default admin app index dashboard.
"""
def __init__(self, *args, **kwargs):
super(DefaultAppIndexDashboard, self).__init__(*args, **kwargs)
# we disable title because its redundant with the model list module
self.title = ''
# append a model list module
self.append(ModelListDashboardModule(
title=self.app_title,
include_list=self.models,
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
title=_('Recent Actions'),
include_list=self.models,
limit=5
))

View File

@ -12,22 +12,65 @@ from admin_tools.utils import AppListElementMixin
class Dashboard(list):
"""
Base class for dashboards.
The Dashboard class is a simple python list that takes three optional
keywords arguments ``title``, ``template`` and ``columns``.
The Dashboard class is a simple python list that has three additional
properties:
>>> d = Dashboard(template='foo.html', columns=3)
>>> d.template
'foo.html'
>>> d.columns
3
>>> d.append(DashboardModule())
>>> d.append(DashboardModule())
>>> len(d)
2
>>> d.pop().__class__.__name__
'DashboardModule'
>>> len(d)
1
``title``
The dashboard title, by default, it is displayed above the dashboard
in a ``h2`` tag. Default value: 'Dashboard'.
``template``
The template to use to render the dashboard.
Default value: 'dashboard/dashboard.html'
``columns``
An integer that represents the number of columns for the dashboard.
Default value: 2.
If you want to customize the look of your dashboard and it's modules, you
can declare css stylesheets and/or javascript files to include when
rendering the dashboard, for example::
from admin_tools.dashboard.models import *
class MyDashboard(Dashboard):
class Media:
css = {'screen': '/media/css/mydashboard.css'}
js = ('/media/js/mydashboard.js',)
Here's an example of a custom dashboard::
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from admin_tools.dashboard.models import *
class MyDashboard(Dashboard):
def render(self, request):
# we want a 3 columns layout
self.columns = 3
# append an app list module for "Applications"
self.append(AppListDashboardModule(
title=_('Applications'),
exclude_list=('django.contrib',),
))
# append an app list module for "Administration"
self.append(AppListDashboardModule(
title=_('Administration'),
include_list=('django.contrib',),
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
enabled=False,
title=_('Recent Actions'),
limit=5
))
Below is a screenshot of the resulting dashboard:
.. image:: images/dashboard_example.png
"""
class Media:
css = {
@ -44,29 +87,29 @@ class Dashboard(list):
def __init__(self, *args, **kwargs):
"""
Dashboard constructor, keyword argument:
``title``
the title to display for your dashboard.
Default value: 'Dashboard'.
``template``
the path to the dashboard template.
Default value: 'dashboard/dashboard.html'.
``columns``
The number of columns for the dashboard. Default value: 2.
Dashboard constructor.
"""
super(Dashboard, self).__init__()
self.title = kwargs.get('title', _('Dashboard'))
self.template = kwargs.get('template', 'dashboard/dashboard.html')
self.columns = kwargs.get('columns', 2)
def render(self, request):
"""
The ``Dashboard.render()`` method is called just before the display
with a ``django.http.HttpRequest`` as unique argument.
Override this method to build your dashboard if you need to access to
the request instance.
"""
pass
class AppIndexDashboard(Dashboard):
"""
Class that represents an app index dashboard, it is very similar to the
standard dashboard except that its constructors receives two arguments:
Class that represents an app index dashboard, app index dashboards are
displayed in the applications index page.
``AppIndexDashboard`` is very similar to the ``Dashboard`` class except
that its constructor receives two extra arguments:
``app_title``
The title of the application
@ -79,64 +122,92 @@ class AppIndexDashboard(Dashboard):
If you want to provide custom app index dashboard, be sure to inherit from
this class instead of the ``Dashboard`` class.
Here's an example of a custom app index dashboard::
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from admin_tools.dashboard.models import *
class MyAppIndexDashboard(AppIndexDashboard):
def render(self, request):
# we don't want a title, it's redundant
self.title = ''
# append a model list module that lists all models
# for the app
self.append(ModelListDashboardModule(
title=self.app_title,
include_list=self.models,
))
# append a recent actions module for the current app
self.append(RecentActionsDashboardModule(
title=_('Recent Actions'),
include_list=self.models,
limit=5
))
Below is a screenshot of the resulting dashboard:
.. image:: images/dashboard_app_index_example.png
"""
def __init__(self, app_title, models, *args, **kwargs):
super(AppIndexDashboard, self).__init__(*args, **kwargs)
self.app_title = app_title
self.models = models
class DashboardModule(object):
"""
Base class for all dashboard modules.
Dashboard modules have the following properties:
``enabled``
Boolean that determines whether the module should be enabled in
the dashboard by default or not. Default value: ``True``.
``draggable``
Boolean that determines whether the module can be draggable or not.
Draggable modules can be re-arranged by users. Default value: ``True``.
``collapsible``
Boolean that determines whether the module is collapsible, this
allows users to show/hide module content. Default: ``True``.
``deletable``
Boolean that determines whether the module can be removed from the
dashboard by users or not. Default: ``True``.
``title``
String that contains the module title, make sure you use the django
gettext functions if your application is multilingual.
Default value: ''.
``title_url``
String that contains the module title URL. If given the module
title will be a link to this URL. Default value: ``None``.
``css_classes``
A list of css classes to be added to the module ``div`` class
attribute. Default value: ``None``.
``pre_content``
Text or HTML content to display above the module content.
Default value: ``None``.
``content``
The module text or HTML content. Default value: ``None``.
``post_content``
Text or HTML content to display under the module content.
Default value: ``None``.
``template``
The template to use to render the module.
Default value: 'dashboard/module.html'.
"""
def __init__(self, *args, **kwargs):
"""
Dashboard module constructor, keywords arguments (all are optional):
``enabled``
Boolean that determines whether the module should be enabled in
the dashboard by default or not. Default value: True.
``draggable``
Boolean that determines whether the module can be draggable or not.
Draggable modules can be re-arranged by users. Default value: True.
``collapsible``
Boolean that determines whether the module is collapsible, this
allows users to show/hide module content. Default: True.
``deletable``
Boolean that determines whether the module can be removed from the
dashboard by users or not. Default: True.
``title``
String that contains the module title, make sure you use the django
gettext functions if your application is multilingual.
Default value: ''.
``title_url``
String that contains the module title URL. If given the module
title will be a link to this URL. Default value: None.
``css_classes``
A list of css classes to be added to the module ``div`` class
attribute. Default value: None.
``pre_content``
Text or HTML content to display above the module content.
Default value: None.
``content``
The module text or HTML content. Default value: None.
``post_content``
Text or HTML content to display under the module content.
Default value: None.
``template``
The template to use to render the module.
Default value: 'dashboard/module.html'.
"""
self.enabled = kwargs.get('enabled', True)
self.draggable = kwargs.get('draggable', True)
self.collapsible = kwargs.get('collapsible', True)
@ -204,19 +275,62 @@ class DashboardModule(object):
return ' '.join(ret)
class TextDashboardModule(DashboardModule):
"""
Dashboard module that displays a list of links.
"""
def __init__(self, *args, **kwargs):
super(TextDashboardModule, self).__init__(*args, **kwargs)
self.entries.append(kwargs.get('text', ''))
class LinkListDashboardModule(DashboardModule):
"""
Dashboard module that displays a list of links.
A module that displays a list of links.
As well as the ``DashboardModule`` properties, the
``LinkListDashboardModule`` takes an extra keyword argument:
``layout``
The layout of the list, possible values are ``stacked`` and ``inline``.
The default value is ``stacked``.
Link list modules entries are simple python dictionaries that can have the
following keys:
``title``
The link title.
``url``
The link URL.
``external``
Boolean that indicates whether the link is an external one or not.
``description``
A string describing the link, it will be the ``title`` attribute of
the html ``a`` tag.
Here's a small example of building a link list module::
from admin_tools.dashboard.models import *
mydashboard = Dashboard()
mydashboard.append(LinkListDashboardModule(
layout='inline',
entries=(
{
'title': 'Python website',
'url': 'http://www.python.org',
'external': True,
'title': 'Python programming language rocks !',
},
{
'title': 'Django website',
'url': 'http://www.djangoproject.com',
'external': True
},
{
'title': 'Some internal link',
'url': '/some/internal/link/',
'external': False
},
)
))
The screenshot of what this code produces:
.. image:: images/linklist_dashboard_module.png
"""
def __init__(self, *args, **kwargs):
@ -229,22 +343,63 @@ class LinkListDashboardModule(DashboardModule):
class AppListDashboardModule(DashboardModule, AppListElementMixin):
"""
Class that represents a dashboard module that lists installed apps.
Module that lists installed apps and their models.
As well as the ``DashboardModule`` properties, the
``AppListDashboardModule`` has two extra properties:
``exclude_list``
A list of apps to exclude, if an app name (e.g. "django.contrib.auth"
starts with an element of this list (e.g. "django.contrib") it won't
appear in the dashboard module.
``include_list``
A list of apps to include, only apps whose name (e.g.
"django.contrib.auth") starts with one of the strings (e.g.
"django.contrib") in the list will appear in the dashboard module.
If no include/exclude list is provided, **all apps** are shown.
Here's a small example of building an app list module::
from admin_tools.dashboard.models import *
mydashboard = Dashboard()
# will only list the django.contrib apps
mydashboard.append(AppListDashboardModule(
title='Administration',
include_list=('django.contrib',)
))
# will list all apps except the django.contrib ones
mydashboard.append(AppListDashboardModule(
title='Applications',
exclude_list=('django.contrib',)
))
The screenshot of what this code produces:
.. image:: images/applist_dashboard_module.png
.. note::
Note that this module takes into account user permissions, for
example, if a user has no rights to change or add a ``Group``, then
the django.contrib.auth.Group model line will not be displayed.
"""
def __init__(self, *args, **kwargs):
super(AppListDashboardModule, self).__init__(*args, **kwargs)
self.title = kwargs.get('title', _('Applications'))
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
self.template = kwargs.get('template',
'dashboard/modules/app_list.html')
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
def render(self, request):
apps = {}
for model, model_admin in admin.site._registry.items():
perms = self._check_perms(request, model, model_admin)
if not perms:
if not perms or ('add' not in perms and 'change' not in perms):
continue
app_label = model._meta.app_label
if app_label not in apps:
@ -270,14 +425,50 @@ class AppListDashboardModule(DashboardModule, AppListElementMixin):
class ModelListDashboardModule(DashboardModule, AppListElementMixin):
"""
Module that lists a set of models.
As well as the ``DashboardModule`` properties, the
``ModelListDashboardModule`` takes two extra keyword arguments:
``include_list``
A list of models to include, only models whose name (e.g.
"blog.comments.Comment") starts with one of the strings (e.g. "blog")
in the include list will appear in the dashboard module.
``exclude_list``
A list of models to exclude, if a model name (e.g.
"blog.comments.Comment" starts with an element of this list (e.g.
"blog.comments") it won't appear in the dashboard module.
Here's a small example of building a model list module::
from admin_tools.dashboard.models import *
mydashboard = Dashboard()
# will only list the django.contrib.auth models
mydashboard.append(ModelListDashboardModule(
title='Authentication',
include_list=('django.contrib.auth',)
))
The screenshot of what this code produces:
.. image:: images/recentactions_dashboard_module.png
.. note::
Note that this module takes into account user permissions, for
example, if a user has no rights to change or add a ``Group``, then
the django.contrib.auth.Group model line will not be displayed.
"""
def __init__(self, *args, **kwargs):
super(ModelListDashboardModule, self).__init__(*args, **kwargs)
self.title = kwargs.get('title', '')
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
self.template = kwargs.get('template',
'dashboard/modules/model_list.html')
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
def render(self, request):
for model, model_admin in admin.site._registry.items():
@ -299,16 +490,47 @@ class ModelListDashboardModule(DashboardModule, AppListElementMixin):
class RecentActionsDashboardModule(DashboardModule):
"""
Module that lists the recent actions for the current user.
As well as the ``DashboardModule`` properties, the
``RecentActionsDashboardModule`` takes three extra keyword arguments:
``include_list``
A list of models to include, only actions for models whose name (e.g.
"blog.comments.Comment") starts with one of the strings (e.g. "blog")
in the include list will appear in the dashboard module.
``exclude_list``
A list of models to exclude, if a model name (e.g.
"blog.comments.Comment" starts with an element of this list (e.g.
"blog.comments") it's recent actions won't appear in the dashboard
module.
``limit``
The maximum number of entries to display. Default value: 10.
Here's a small example of building a recent actions module::
from admin_tools.dashboard.models import *
mydashboard = Dashboard()
# will only list the django.contrib apps
mydashboard.append(RecentActionsDashboardModule(
title='Django CMS recent actions',
include_list=('cms',)
))
The screenshot of what this code produces:
.. image:: images/recentactions_dashboard_module.png
"""
def __init__(self, *args, **kwargs):
super(RecentActionsDashboardModule, self).__init__(*args, **kwargs)
self.title = kwargs.get('title', _('Recent Actions'))
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
self.limit = kwargs.get('limit', [])
self.template = kwargs.get('template',
'dashboard/modules/recent_actions.html')
self.include_list = kwargs.get('include_list', [])
self.exclude_list = kwargs.get('exclude_list', [])
self.limit = kwargs.get('limit', 10)
def render(self, request):
from django.contrib.admin.models import LogEntry
@ -327,6 +549,39 @@ class RecentActionsDashboardModule(DashboardModule):
class FeedDashboardModule(DashboardModule):
"""
Class that represents a feed dashboard module.
.. important::
This class uses the
`Universal Feed Parser module <http://www.feedparser.org/>`_ to parse
the feeds, so you'll need to install it, all feeds supported by
FeedParser are thus supported by the FeedDashboardModule.
As well as the ``DashboardModule`` properties, the ``FeedDashboardModule``
takes two extra keyword arguments:
``feed_url``
The URL of the feed.
``limit``
The maximum number of feed entries to display. Default value: None,
which means that all entries are displayed.
Here's a small example of building a recent actions module::
from admin_tools.dashboard.models import *
mydashboard = Dashboard()
# will only list the django.contrib apps
mydashboard.append(FeedDashboardModule(
title=_('Latest Django News'),
feed_url='http://www.djangoproject.com/rss/weblog/',
limit=5
))
The screenshot of what this code produces:
.. image:: images/feed_dashboard_module.png
"""
def __init__(self, *args, **kwargs):
super(FeedDashboardModule, self).__init__(*args, **kwargs)
@ -357,3 +612,120 @@ class FeedDashboardModule(DashboardModule):
# no date for certain feeds
pass
self.entries.append(entry)
class DefaultIndexDashboard(Dashboard):
"""
The default dashboard displayed on the admin index page.
To change the default dashboard you'll have to type the following from the
commandline in your project root directory::
python manage.py customdashboard
And then set the ``ADMIN_TOOLS_INDEX_DASHBOARD`` settings variable to
point to your custom index dashboard class.
"""
def __init__(self, *args, **kwargs):
super(DefaultIndexDashboard, self).__init__(*args, **kwargs)
# append a link list module for "quick links"
self.append(LinkListDashboardModule(
title=_('Quick links'),
layout='inline',
draggable=False,
deletable=False,
collapsible=False,
entries=[
{
'title': _('Return to site'),
'url': '/',
},
{
'title': _('Change password'),
'url': reverse('admin:password_change'),
},
{
'title': _('Log out'),
'url': reverse('admin:logout')
},
]
))
# append an app list module for "Applications"
self.append(AppListDashboardModule(
title=_('Applications'),
exclude_list=('django.contrib',),
))
# append an app list module for "Administration"
self.append(AppListDashboardModule(
title=_('Administration'),
include_list=('django.contrib',),
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
enabled=False,
title=_('Recent Actions'),
limit=5
))
# append a feed module
self.append(FeedDashboardModule(
enabled=False,
title=_('Latest Django News'),
feed_url='http://www.djangoproject.com/rss/weblog/',
limit=5
))
# append another link list module for "support".
self.append(LinkListDashboardModule(
title=_('Support'),
entries=[
{
'title': _('Django documentation'),
'url': 'http://docs.djangoproject.com/',
'external': True,
},
{
'title': _('Django "django-users" mailing list'),
'url': 'http://groups.google.com/group/django-users',
'external': True,
},
{
'title': _('Django irc channel'),
'url': 'irc://irc.freenode.net/django',
'external': True,
},
]
))
class DefaultAppIndexDashboard(AppIndexDashboard):
"""
The default dashboard displayed on the applications index page.
To change the default dashboard you'll have to type the following from the
commandline in your project root directory::
python manage.py customdashboard
And then set the ``ADMIN_TOOLS_APP_INDEX_DASHBOARD`` settings variable to
point to your custom app index dashboard class.
"""
def render(self, request):
# we disable title because its redundant with the model list module
self.title = ''
# append a model list module
self.append(ModelListDashboardModule(
title=self.app_title,
include_list=self.models,
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
title=_('Recent Actions'),
include_list=self.models,
limit=5
))

View File

@ -17,18 +17,79 @@ class CustomIndexDashboard(Dashboard):
"""
Document your custom dashboard.
"""
def __init__(self, *args, **kwargs):
super(CustomIndexDashboard, self).__init__(*args, **kwargs)
# append your modules here, example:
self.append(AppListDashboardModule(
title=_('Modules'),
def render(self, request):
# append a link list module for "quick links"
self.append(LinkListDashboardModule(
title=_('Quick links'),
layout='inline',
draggable=False,
deletable=False,
collapsible=False,
entries=[
{
'title': _('Return to site'),
'url': '/',
},
{
'title': _('Change password'),
'url': reverse('admin:password_change'),
},
{
'title': _('Log out'),
'url': reverse('admin:logout')
},
]
))
# append an app list module for "Applications"
self.append(AppListDashboardModule(
title=_('Applications'),
exclude_list=('django.contrib',),
))
# append an app list module for "Administration"
self.append(AppListDashboardModule(
title=_('Administration'),
include_list=('django.contrib',),
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
enabled=False,
title=_('Recent Actions'),
limit=5
))
# append a feed module
self.append(FeedDashboardModule(
enabled=False,
title=_('Latest Django News'),
feed_url='http://www.djangoproject.com/rss/weblog/',
limit=5
))
# append another link list module for "support".
self.append(LinkListDashboardModule(
title=_('Support'),
entries=[
{
'title': _('Django documentation'),
'url': 'http://docs.djangoproject.com/',
'external': True,
},
{
'title': _('Django "django-users" mailing list'),
'url': 'http://groups.google.com/group/django-users',
'external': True,
},
{
'title': _('Django irc channel'),
'url': 'irc://irc.freenode.net/django',
'external': True,
},
]
))
# to activate your app index dashboard you must add the following to your
# project's settings.py file:
@ -38,16 +99,19 @@ class CustomAppIndexDashboard(AppIndexDashboard):
"""
Document your custom app index dashboard.
"""
def __init__(self, app_title, models, *args, **kwargs):
super(CustomAppIndexDashboard, self).__init__(*args, **kwargs)
def render(self, request):
# we disable title because its redundant with the model list module
self.title = ''
# append your modules here, example:
self.append(AppListDashboardModule(
title=_('Modules'),
include_list=models,
# append a model list module
self.append(ModelListDashboardModule(
title=self.app_title,
include_list=self.models,
))
# append a recent actions module
self.append(RecentActionsDashboardModule(
title=_('Recent Actions'),
limit=5,
include_list=models,
include_list=self.models,
limit=5
))

View File

@ -4,10 +4,7 @@
{% spaceless %}
{% for entry in module.entries %}
<li class="{% cycle 'odd' 'even' %}">
<a{% if entry.external %} class="external-link"{% endif %} href="{{ entry.url }}">{{ entry.title }}</a>
{% if entry.description %}
<p class="linklist-description">{{ entry.description }}</p>
{% endif %}
<a{% if entry.external %} class="external-link"{% endif %} href="{{ entry.url }}" {% if entry.description %} title="{{ entry.description }}"{% endif %}>{{ entry.title }}</a>
</li>
{% endfor %}
{% endspaceless %}

View File

@ -24,6 +24,7 @@ def render_dashboard(context, dashboard=None):
"""
if not dashboard:
dashboard = get_dashboard_from_context(context)
dashboard.render(context['request'])
context.update({
'template': dashboard.template,
'dashboard': dashboard,

View File

@ -9,9 +9,8 @@ from django.core.urlresolvers import reverse
from django.http import HttpRequest
from django.utils.importlib import import_module
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from admin_tools.dashboard import Registry
from admin_tools.dashboard.models import *
from admin_tools.dashboard.default_dashboard import *
def get_dashboard_from_context(context):
@ -24,15 +23,18 @@ def get_dashboard_from_context(context):
try:
app = context['app_list'][0]
models = []
app_label = app['name']
app_label = None
app_title = app['name']
for model, model_admin in admin.site._registry.items():
if app['name'] == model._meta.app_label.title():
app_label = model._meta.app_label
split = model.__module__.find(model._meta.app_label)
app_label = model.__module__[0:split] + model._meta.app_label
app_title = model._meta.app_label.title
for m in app['models']:
if m['name'] == capfirst(model._meta.verbose_name_plural):
mod = '%s.%s' % (model.__module__, model.__name__)
models.append(mod)
return get_app_index_dashboard(request, app_label, models)
return get_app_index_dashboard(request, app_label, app_title, models)
except KeyError:
return get_app_index_dashboard(request, '', [])
@ -41,47 +43,45 @@ def get_index_dashboard(request):
"""
Returns the admin dashboard defined by the user or the default one.
"""
dashboard_cls = getattr(settings, 'ADMIN_TOOLS_INDEX_DASHBOARD', False)
if dashboard_cls:
try:
mod, inst = dashboard_cls.rsplit('.', 1)
mod = import_module(mod)
return getattr(mod, inst)()
except:
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_INDEX_DASHBOARD '
'setting variable cannot be imported'
))
return DefaultIndexDashboard()
dashboard_cls = getattr(
settings,
'ADMIN_TOOLS_INDEX_DASHBOARD',
'admin_tools.dashboard.models.DefaultIndexDashboard'
)
try:
mod, inst = dashboard_cls.rsplit('.', 1)
mod = import_module(mod)
except:
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_INDEX_DASHBOARD '
'setting variable cannot be imported'
))
return getattr(mod, inst)()
def get_app_index_dashboard(request, app_label='', model_list=[]):
def get_app_index_dashboard(request, app_label=None, app_title='',
model_list=[]):
"""
Returns the admin dashboard defined by the user or the default one.
"""
app_title = app_label.title()
# try to discover corresponding app dashboard module
mod_name = getattr(settings, 'ADMIN_TOOLS_APP_INDEX_DASHBOARD_MODULE', 'dashboard')
mod_class = getattr(settings, 'ADMIN_TOOLS_APP_INDEX_DASHBOARD_CLASS', '%sDashboard' % capfirst(app_label))
# if an app has registered its own dashboard, use it
if app_label is not None and app_label in Registry.registry:
return Registry.registry[app_label](app_title, model_list)
# try to discover a general app_index dashboard (with fallback to the
# default dashboard)
dashboard_cls = getattr(
settings,
'ADMIN_TOOLS_APP_INDEX_DASHBOARD',
'admin_tools.dashboard.models.DefaultAppIndexDashboard'
)
try:
mod = import_module('%s.%s' % (app_label, mod_name))
return getattr(mod, mod_class)(app_title, model_list)
mod, inst = dashboard_cls.rsplit('.', 1)
mod = import_module(mod)
except:
pass
# try to discover a general app_index dashboard
dashboard_cls = getattr(settings, 'ADMIN_TOOLS_APP_INDEX_DASHBOARD', False)
if dashboard_cls:
try:
mod, inst = dashboard_cls.rsplit('.', 1)
mod = import_module(mod)
return getattr(mod, inst)(app_title, model_list)
except:
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_APP_INDEX_DASHBOARD '
'setting variable cannot be imported'
))
# fallback to default dashboard
return DefaultAppIndexDashboard(app_title, model_list)
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_APP_INDEX_DASHBOARD '
'setting variable cannot be imported'
))
return getattr(mod, inst)(app_title, model_list)

View File

@ -5,26 +5,46 @@ This module contains the base classes for menu and menu items.
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from admin_tools.utils import AppListElementMixin
class Menu(list):
"""
Base class for menus.
The Menu class is a simple python list that takes an optional keyword
argument ``template``.
The Menu class is a simple python list that has an extra property:
``template``
The template to use to render the menu.
Default value: "menu/menu.html".
>>> m = Menu(template='foo.html')
>>> m.template
'foo.html'
>>> m.append(MenuItem())
>>> m.append(MenuItem())
>>> len(m)
2
>>> m.pop().__class__.__name__
'MenuItem'
>>> len(m)
1
If you want to customize the look of your menu and it's menu items, you
can declare css stylesheets and/or javascript files to include when
rendering the menu, for example::
from admin_tools.menu.models import *
class MyMenu(Menu):
class Media:
css = {'screen': '/media/css/mymenu.css'}
js = ('/media/js/mymenu.js',)
Here's an example of a custom menu::
from admin_tools.menu.models import *
class MyMenu(Menu):
def render(self, request):
self.append(MenuItem(title='Home', url=reverse('admin:index')))
self.append(AppListMenuItem(title='Applications'))
item = MenuItem('Multi level menu item')
item.append(MenuItem('Child 1'))
item.append(MenuItem('Child 2'))
self.append(item)
Below is a screenshot of the resulting menu:
.. image:: images/menu_example.png
"""
class Media:
@ -42,48 +62,56 @@ class Menu(list):
super(Menu, self).__init__()
self.template = kwargs.get('template', 'menu/menu.html')
def is_empty(self):
def render(self, request):
"""
Return True if the menu is empty and false otherwise.
The ``Menu.render()`` method is called just before the display with a
``django.http.HttpRequest`` as unique argument.
Override this method to build your menu if you need to access to the
request instance.
"""
return len([i for i in self]) == 0
pass
class MenuItem(list):
"""
Base class for menu items.
A menu item is a simple python list that takes some optional keywords
arguments. Menu items can be nested.
A menu item is a simple python list that has some additional properties:
``title``
String that contains the menu item title, make sure you use the
django gettext functions if your application is multilingual.
Default value: 'Untitled menu item'.
``url``
String that contains the menu item URL.
Default value: '#'.
``css_classes``
A list of css classes to be added to the menu item ``li`` class
attribute. Default value: None.
``accesskey``
The menu item accesskey. Default value: None.
``description``
An optional string that will be used as the ``title`` attribute of
the menu-item ``a`` tag. Default value: None.
``template``
The template to use to render the menu item.
Default value: 'menu/item.html'.
Menu items can be nested so for example you can do the following::
from admin_tools.menu.models import *
mymenu = Menu()
item = MenuItem(title='Foo')
item.append(MenuItem(title='Bar'))
mymenu.append(item)
"""
def __init__(self, *args, **kwargs):
"""
MenuItem module constructor, keywords arguments (all are optional):
``title``
String that contains the menu item title, make sure you use the
django gettext functions if your application is multilingual.
Default value: 'Untitled menu item'.
``url``
String that contains the menu item URL.
Default value: '#'.
``css_classes``
A list of css classes to be added to the menu item ``li`` class
attribute. Default value: None.
``accesskey``
The menu item accesskey. Default value: None.
``description``
An optional string that will be used as the ``title`` attribute of
the menu-item ``a`` tag. Default value: None.
``template``
The template to use to render the menu item.
Default value: 'menu/item.html'.
"""
super(MenuItem, self).__init__()
self.title = kwargs.get('title', 'Untitled menu item')
self.url = kwargs.get('url', '#')
@ -93,12 +121,66 @@ class MenuItem(list):
self.template = kwargs.get('template', 'menu/item.html')
def render(self, request):
"""
The ``MenuItem.render()`` is called just before the display with a
``django.http.HttpRequest`` as unique argument.
You can use it to build your item when you need to access the request
instance, for example::
from admin_tools.menu.models import *
class MyMenuItem(MenuItem):
def render(self, request):
if request.user.username == 'foo':
self.title = 'Foo'
else:
self.title = 'Bar'
mymenu = Menu()
mymenu.append(MyMenuItem())
"""
pass
class AppListMenuItem(MenuItem, AppListElementMixin):
"""
Class that represents a menu item that lists installed apps.
A menu item that lists installed apps an their models.
As well as the ``MenuItem`` properties, the ``AppListMenuItem`` has two
extra properties:
``exclude_list``
A list of apps to exclude, if an app name (e.g. "django.contrib.auth"
starts with an element of this list (e.g. "django.contrib") it won't
appear in the menu item.
``include_list``
A list of apps to include, only apps whose name (e.g.
"django.contrib.auth") starts with one of the strings (e.g.
"django.contrib") in the list will appear in the menu item.
If no include/exclude list is provided, **all apps** are shown.
Here's a small example of building an app list menu item::
from admin_tools.menu.models import *
mymenu = Menu()
# will list all apps except the django.contrib ones
mymenu.append(AppListMenuItem(
title='Applications',
exclude_list=('django.contrib',)
))
The screenshot of what this code produces:
.. image:: images/applist_menu_item.png
.. note::
Note that this module takes into account user permissions, for
example, if a user has no rights to change or add a ``Group``, then
the django.contrib.auth.Group model child item will not be displayed.
"""
def __init__(self, *args, **kwargs):
@ -134,3 +216,29 @@ class AppListMenuItem(MenuItem, AppListElementMixin):
for model_dict in apps[app]['models']:
item.append(MenuItem(**model_dict))
self.append(item)
class DefaultMenu(Menu):
"""
The default menu displayed by default by django-admin-tools.
To change the default menu you'll have to type the following from the
commandline in your project root directory::
python manage.py custommenu
And then set the ``ADMIN_TOOLS_MENU`` settings variable to point to your
custom menu class.
"""
def render(self, request):
self.append(MenuItem(
title=_('Dashboard'),
url=reverse('admin:index')
))
self.append(AppListMenuItem(
title=_('Applications'),
exclude_list=('django.contrib',),
))
self.append(AppListMenuItem(
title=_('Administration'),
include_list=('django.contrib',),
))

View File

@ -11,7 +11,7 @@ var hover_ie6 = function() {
window.onload = hover_ie6;
</script>
<![endif]-->
{% if not menu.is_empty %}
{% if menu %}
<ul id="navigation-menu">
{% for item in menu %}{% render_menu_item item forloop.counter %}{% endfor %}
</div>

View File

@ -17,15 +17,16 @@ class CustomMenu(Menu):
"""
Returns the admin menu defined by the user or the default one.
"""
def __init__(self, *args, **kwargs):
super(CustomMenu, self).__init__(*args, **kwargs)
# append your menu items here, for example:
def render(self, request):
self.append(MenuItem(
title=_('Home'),
title=_('Dashboard'),
url=reverse('admin:index')
))
self.append(MenuItem(
title=_('Some link'),
url='http://example.com'
self.append(AppListMenuItem(
title=_('Applications'),
exclude_list=('django.contrib',),
))
self.append(AppListMenuItem(
title=_('Administration'),
include_list=('django.contrib',),
))

View File

@ -23,6 +23,7 @@ def render_menu(context, menu=None):
"""
if menu is None:
menu = get_admin_menu(context['request'])
menu.render(context['request'])
context.update({
'template': menu.template,
'menu': menu,

View File

@ -14,29 +14,17 @@ def get_admin_menu(request):
"""
Returns the admin menu defined by the user or the default one.
"""
menu_cls = getattr(settings, 'ADMIN_TOOLS_MENU', False)
if menu_cls:
try:
mod, inst = menu_cls.rsplit('.', 1)
mod = import_module(mod)
return getattr(mod, inst)()
except:
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_MENU setting variable '
'cannot be imported'
))
admin_menu = Menu()
admin_menu.append(MenuItem(
title=_('Dashboard'),
url=reverse('admin:index')
))
admin_menu.append(AppListMenuItem(
title=_('Applications'),
exclude_list=('django.contrib',),
))
admin_menu.append(AppListMenuItem(
title=_('Administration'),
include_list=('django.contrib',),
))
return admin_menu
menu_cls = getattr(
settings,
'ADMIN_TOOLS_MENU',
'admin_tools.menu.models.DefaultMenu'
)
try:
mod, inst = menu_cls.rsplit('.', 1)
mod = import_module(mod)
except:
raise ImproperlyConfigured((
'The class pointed by your ADMIN_TOOLS_MENU setting variable '
'cannot be imported'
))
return getattr(mod, inst)()

View File

@ -16,7 +16,9 @@ import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.append(os.path.abspath('.'))
sys.path.append(os.path.abspath('..'))
# required for autodoc
os.environ['DJANGO_SETTINGS_MODULE'] = 'django.conf.global_settings'
# -- General configuration -----------------------------------------------------

102
docs/configuration.rst Normal file
View File

@ -0,0 +1,102 @@
.. _configuration:
Configuring django-admin-tools
==============================
Basic configuration
-------------------
Once installed, you can add django-admin-tools to any Django-based
project you're developing.
django-admin-tools is composed of several modules:
* admin_tools.theming: an app that makes it easy to customize the look
and feel of the admin interface;
* admin_tools.menu: a customizable navigation menu that sits on top of
every django administration index page;
* admin_tools.dashboard: a customizable dashboard that replaces the django
administration index page.
Required settings
~~~~~~~~~~~~~~~~~
First make sure you have the following template context processors
installed::
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.request',
)
Then, add the django-admin-tools modules to the ``INSTALLED_APPS`` like
this::
INSTALLED_APPS = (
'admin_tools.theming',
'admin_tools.menu',
'admin_tools.dashboard',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.admin'
# ...other installed applications...
)
.. note::
it is very important that you put the admin_tools modules **before**
the ``django.contrib.admin module``, because django-admin-tools
overrides the default django admin templates, and this will not work
otherwise.
django-admin-tools is modular, so if you want to disable a particular
module, just remove or comment it in your ``INSTALLED_APPS``.
For example, if you just want to use the dashboard::
INSTALLED_APPS = (
'admin_tools.dashboard',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.admin'
# ...other installed applications...
)
Setting up the django-admin-tools media files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To do this you have two options:
* create a symbolic link to the django-admin-tools media files to your
``MEDIA_ROOT`` directory, for example::
ln -s /usr/local/lib/python2.6/dist-packages/admin_tools/media/admin_tools /path/to/yourproject/media/
* copy the django-admin-tools media files to your ``MEDIA_ROOT`` directory,
for example::
cp -r /usr/local/lib/python2.6/dist-packages/admin_tools/media/admin_tools /path/to/yourproject/media/
Available settings variables
----------------------------
``ADMIN_TOOLS_MENU``
The path to your custom menu class, for example
"yourproject.menu.CustomMenu".
``ADMIN_TOOLS_INDEX_DASHBOARD``
The path to your custom index dashboard, for example
"yourproject.dashboard.CustomIndexDashboard".
``ADMIN_TOOLS_APP_INDEX_DASHBOARD``
The path to your custom app index dashboard, for example
"yourproject.dashboard.CustomAppIndexDashboard".
``ADMIN_TOOLS_THEMING_CSS``
The path to your theming css stylesheet, relative to your MEDIA_URL,
for example::
ADMIN_TOOLS_THEMING_CSS = 'css/theming.css'

View File

@ -6,21 +6,110 @@ Customization of the django-admin-tools modules
Introduction
------------
todo: write docs for "Customizing introduction"
django-admin-tools is very easy to customize, you can override the
admin menu, the index dashboard and the app index dashboard.
For this django-admin-tools provides two management commands:
* ``custommenu``
* ``customdashboard``
Customizing the navigation menu
-------------------------------
todo: write docs for "Customizing the navigation menu"
To customize the admin menu, the first step is to do the following::
python manage.py custommenu
This will create a file named ``menu.py`` in your project directory.
If for some reason you want another file name, you can do::
python manage.py custommenu somefile.py
The created file contains a class that is a copy of the default menu,
it is named ``CustomMenu``, you can rename it if you want but if you do
so, make sure you put the correct class name in your ADMIN_TOOLS_MENU
settings variable.
.. note::
You could have done the above by hand, without using the
``custommenu`` management command, but it's simpler with it.
Now you need to tell django-admin-tools to use your custom menu instead
of the default one, open your settings.py file and add the following::
ADMIN_TOOLS_MENU = 'yourproject.menu.CustomMenu'
Obviously, you need to change "yourproject" to the real project name,
if you have chosen a different file name or if you renamed the menu
class, you'll also need to change the above string to reflect your
modifications.
At this point the menu displayed in the admin is your custom menu, now
you can read :ref:`the menu and menu items API documentation <menu>`
to learn how to create your custom menu.
Customizing the dashboards
--------------------------
todo: write docs for "Customizing the dashboards"
To customize the index and app index dashboards, the first step is to do
the following::
python manage.py customdashboard
This will create a file named ``dashboard.py`` in your project directory.
If for some reason you want another file name, you can do::
python manage.py customdashboard somefile.py
The created file contains two classes:
* The ``CustomIndexDashboard`` class that corresponds to the admin
index page dashboard;
* The ``CustomAppIndexDashboard`` class that corresponds to the
index page of each installed application.
You can rename theses classes if you want but if you do so, make sure
adjust the ``ADMIN_TOOLS_INDEX_DASHBOARD`` and
``ADMIN_TOOLS_APP_INDEX_DASHBOARD`` settings variables to match your
class names.
.. note::
You could have done the above by hand, without using the
``customdashboard`` management command, but it's simpler with it.
Customizing the look and feel
-----------------------------
Now you need to tell django-admin-tools to use your custom dashboard(s).
Open your settings.py file and add the following::
todo: write docs for "Customizing the look and feel"
ADMIN_TOOLS_INDEX_DASHBOARD = 'yourproject.dashboard.CustomIndexDashboard'
ADMIN_TOOLS_APP_INDEX_DASHBOARD = 'yourproject.dashboard.CustomAppIndexDashboard'
If you only want a custom index dashboard, you would just need the first
line. Obviously, you need to change "yourproject" to the real project name,
if you have chosen a different file name or if you renamed the dashboard
classes, you'll also need to change the above string to reflect your
modifications.
At this point the dashboards displayed in the index and the app index
should be your custom dashboards, now you can read
:ref:`the dashboard and dashboard modules API documentation <dashboard>`
to learn how to create your custom dashboard.
Customizing the theme
---------------------
.. warning::
The theming support is still very basic and I'm still not sure it's
a good idea, so do not rely to much on it for the moment.
This is very simple, just configure the ``ADMIN_TOOLS_THEMING_CSS`` to
point to your custom css file, for example::
ADMIN_TOOLS_THEMING_CSS = 'css/theming.css'
A good start is to copy the
``admin_tools/media/admin_tools/css/theming.css`` to your custom file and
to modify it to suits your needs.

51
docs/dashboard.rst Normal file
View File

@ -0,0 +1,51 @@
.. _dashboard:
The django-admin-tools dashboard and dashboard modules API
==========================================================
This section describe the API of the django-admin-tools dashboard and
dashboard modules.
Make sure you read this before creating your custom dashboard and
custom modules.
The ``Dashboard`` class
-----------------------
.. autoclass:: admin_tools.dashboard.models.Dashboard
:members:
The ``AppIndexDashboard`` class
-------------------------------
.. autoclass:: admin_tools.dashboard.models.AppIndexDashboard
:members:
The ``DashboardModule`` class
-----------------------------
.. autoclass:: admin_tools.dashboard.models.DashboardModule
:members:
The ``LinkListDashboardModule`` class
-------------------------------------
.. autoclass:: admin_tools.dashboard.models.LinkListDashboardModule
:members:
The ``AppListDashboardModule`` class
------------------------------------
.. autoclass:: admin_tools.dashboard.models.AppListDashboardModule
:members:
The ``RecentActionsDashboardModule`` class
------------------------------------------
.. autoclass:: admin_tools.dashboard.models.RecentActionsDashboardModule
:members:
The ``FeedDashboardModule`` class
---------------------------------
.. autoclass:: admin_tools.dashboard.models.FeedDashboardModule
:members:

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -8,7 +8,16 @@ Welcome to django-admin-tools's documentation!
This documentation covers the latest release of django-admin-tools, a
collection of extensions and tools for the
`Django <http://www.djangoproject.com>`_ administration interface.
`Django <http://www.djangoproject.com>`_ administration interface,
django-admin-tools includes:
* a full featured and customizable dashboard (for the admin index page
and the admin applications index pages),
* a customizable menu bar,
* tools to make admin theming easier.
It was originally developed for django-cms, and then extracted to this
pluggable app.
To get up and running quickly, consult the :ref:`quick-start guide
<quickstart>`, which describes all the necessary steps to install
@ -23,4 +32,8 @@ Contents:
quickstart
installation
configuration
customization
menu
dashboard
integration

6
docs/integration.rst Normal file
View File

@ -0,0 +1,6 @@
.. _integration:
Integration with third party applications
=========================================
todo: write doc for "Integration with third party applications" section.

25
docs/menu.rst Normal file
View File

@ -0,0 +1,25 @@
.. _menu:
The django-admin-tools menu and menu items API
==============================================
This section describe the API of the django-admin-tools menu and menu items.
Make sure you read this before creating your custom menu.
The ``Menu`` class
------------------
.. autoclass:: admin_tools.menu.models.Menu
:members:
The ``MenuItem`` class
----------------------
.. autoclass:: admin_tools.menu.models.MenuItem
:members:
The ``AppListMenuItem`` class
-----------------------------
.. autoclass:: admin_tools.menu.models.AppListMenuItem
:members:

View File

@ -34,19 +34,8 @@ Using ``pip``, type::
Basic configuration
-------------------
Once installed, you can add django-admin-tools to any Django-based
project you're developing.
django-admin-tools is composed of several modules:
* admin_tools.theming: an app that makes it easy to customize the look
and feel of the admin interface;
* admin_tools.menu: a customizable navigation menu that sits on top of
every django administration index page;
* admin_tools.dashboard: a customizable dashboard that replaces the django
administration index page.
For a more detailed guide on how to configure django-admin-tools, please
consult :ref:`the configuration section <configuration>`.
Required settings
~~~~~~~~~~~~~~~~~
@ -72,7 +61,7 @@ this::
# ...other installed applications...
)
.. note::
.. important::
it is very important that you put the admin_tools modules **before**
the ``django.contrib.admin module``, because django-admin-tools
overrides the default django admin templates, and this will not work
@ -80,16 +69,6 @@ this::
django-admin-tools is modular, so if you want to disable a particular
module, just remove or comment it in your ``INSTALLED_APPS``.
For example, if you just want to use the dashboard::
INSTALLED_APPS = (
'admin_tools.dashboard',
'django.contrib.auth',
'django.contrib.sites',
'django.contrib.admin'
# ...other installed applications...
)
Setting up the django-admin-tools media files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~