Commits

David Jean Louis  committed 7649921 Merge

Merged kmike changes

  • Participants
  • Parent commits 6447940, 1fecc05

Comments (0)

Files changed (12)

File admin_tools/dashboard/__init__.py

-"""
-Dashboard registry.
-"""
 from admin_tools.dashboard.dashboards import *
-
-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)
+from admin_tools.dashboard.registry import *

File admin_tools/dashboard/dashboards.py

         from admin_tools.dashboard import modules, Dashboard
 
         class MyDashboard(Dashboard):
+
+            # we want a 3 columns layout
+            columns = 3
+
             def __init__(self, **kwargs):
-                # we want a 3 columns layout
-                self.columns = 3
 
                 # append an app list module for "Applications"
                 self.children.append(modules.AppList(
 
     .. image:: images/dashboard_example.png
     """
+
+    title = _('Dashboard')
+    template = 'admin_tools/dashboard/dashboard.html'
+    columns = 2
+    children = None
+
     class Media:
         css = ()
         js  = ()
 
     def __init__(self, **kwargs):
-        """
-        Dashboard constructor.
-        """
-        self.title = kwargs.get('title', _('Dashboard'))
-        self.template = kwargs.get('template', 'admin_tools/dashboard/dashboard.html')
-        self.columns = kwargs.get('columns', 2)
-        self.children = kwargs.get('children', [])
+        for key in kwargs:
+            if hasattr(self.__class__, key):
+                setattr(self, key, kwargs[key])
+        self.children = self.children or []
 
     def init_with_context(self, context):
         """
         from admin_tools.dashboard import modules, AppIndexDashboard
 
         class MyAppIndexDashboard(AppIndexDashboard):
-            def __init__(self, **kwargs):
-                AppIndexDashboard.__init__(self, **kwargs)
-                # we don't want a title, it's redundant
-                self.title = ''
+
+            # we don't want a title, it's redundant
+            title = ''
+
+            def __init__(self, app_title, models, **kwargs):
+                AppIndexDashboard.__init__(self, app_title, models, **kwargs)
 
                 # append a model list module that lists all models
-                # for the app
-                self.children.append(modules.ModelList(
-                    title=self.app_title,
-                    include_list=self.models,
-                ))
-
-                # append a recent actions module for the current app
-                self.children.append(modules.RecentActions(
-                    title=_('Recent Actions'),
-                    include_list=self.models,
-                    limit=5
-                ))
+                # for the app and a recent actions module for the current app
+                self.children += [
+                    modules.ModelList(self.app_title, include_list=self.models),
+                    modules.RecentActions(
+                        include_list=self.models,
+                        limit=5
+                    )
+                ]
 
     Below is a screenshot of the resulting dashboard:
 
     .. image:: images/dashboard_app_index_example.png
     """
+
+    models = None
+    app_title = None
+
     def __init__(self, app_title, models, **kwargs):
+        kwargs.update({'app_title': app_title, 'models': models})
         super(AppIndexDashboard, self).__init__(**kwargs)
-        self.app_title = app_title
-        self.models = models
 
     def get_app_model_classes(self):
         """
 
         # append a link list module for "quick links"
         self.children.append(modules.LinkList(
-            title=_('Quick links'),
+            _('Quick links'),
             layout='inline',
             draggable=False,
             deletable=False,
             collapsible=False,
             children=[
-                {
-                    'title': _('Return to site'),
-                    'url': '/',
-                },
-                {
-                    'title': _('Change password'),
-                    'url': reverse('admin:password_change'),
-                },
-                {
-                    'title': _('Log out'),
-                    'url': reverse('admin:logout')
-                },
+                [_('Return to site'), '/'],
+                [_('Change password'), reverse('admin:password_change')],
+                [_('Log out'), reverse('admin:logout')],
             ]
         ))
 
         # append an app list module for "Applications"
         self.children.append(modules.AppList(
-            title=_('Applications'),
+            _('Applications'),
             exclude_list=('django.contrib',),
         ))
 
         # append an app list module for "Administration"
         self.children.append(modules.AppList(
-            title=_('Administration'),
+            _('Administration'),
             include_list=('django.contrib',),
         ))
 
         # append a recent actions module
-        self.children.append(modules.RecentActions(
-            title=_('Recent Actions'),
-            limit=5
-        ))
+        self.children.append(modules.RecentActions(_('Recent Actions'), 5))
 
         # append a feed module
         self.children.append(modules.Feed(
-            title=_('Latest Django News'),
+            _('Latest Django News'),
             feed_url='http://www.djangoproject.com/rss/weblog/',
             limit=5
         ))
 
         # append another link list module for "support".
         self.children.append(modules.LinkList(
-            title=_('Support'),
+            _('Support'),
             children=[
                 {
                     'title': _('Django documentation'),
     And then set the ``ADMIN_TOOLS_APP_INDEX_DASHBOARD`` settings variable to
     point to your custom app index dashboard class.
     """
+
+    # we disable title because its redundant with the model list module
+    title = ''
+
     def __init__(self, *args, **kwargs):
         AppIndexDashboard.__init__(self, *args, **kwargs)
 
-        # we disable title because its redundant with the model list module
-        self.title = ''
-
         # append a model list module
         self.children.append(modules.ModelList(
-            title=self.app_title,
+            self.app_title,
             include_list=self.models,
         ))
 
         # append a recent actions module
         self.children.append(modules.RecentActions(
-            title=_('Recent Actions'),
+            _('Recent Actions'),
             include_list=self.get_app_content_types(),
             limit=5
         ))

File admin_tools/dashboard/models.py

 
 # warnings for deprecated imports
 from admin_tools.deprecate_utils import import_path_is_changed
-from admin_tools import dashboard
+from admin_tools.dashboard import dashboards
 from admin_tools.dashboard import modules
 
 class Dashboard(
               'admin_tools.dashboard.models.Dashboard',
               'admin_tools.dashboard.Dashboard'
           ),
-          dashboard.Dashboard
+          dashboards.Dashboard
       ): pass
 
 class DefaultIndexDashboard(
               'admin_tools.dashboard.models.DefaultIndexDashboard',
               'admin_tools.dashboard.DefaultIndexDashboard',
           ),
-          dashboard.DefaultIndexDashboard
+          dashboards.DefaultIndexDashboard
       ):pass
 
 class DefaultAppIndexDashboard(
               'admin_tools.dashboard.models.DefaultAppIndexDashboard',
               'admin_tools.dashboard.DefaultAppIndexDashboard'
           ),
-          dashboard.DefaultAppIndexDashboard
+          dashboards.DefaultAppIndexDashboard
       ):pass
 
 class AppIndexDashboard(
               'admin_tools.dashboard.models.AppIndexDashboard',
               'admin_tools.dashboard.AppIndexDashboard'
           ),
-          dashboard.AppIndexDashboard
+          dashboards.AppIndexDashboard
       ):pass
 
 

File admin_tools/dashboard/modules.py

 """
 Module where admin tools dashboard modules classes are defined.
 """
-
 from django.utils.text import capfirst
 from django.core.urlresolvers import reverse
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import ugettext_lazy as _
-
 from admin_tools.utils import AppListElementMixin
-
+from django.utils.itercompat import is_iterable
 
 class DashboardModule(object):
     """
         The template to use to render the module.
         Default value: 'admin_tools/dashboard/module.html'.
     """
-    def __init__(self, **kwargs):
-        self.enabled = kwargs.get('enabled', True)
-        self.draggable = kwargs.get('draggable', True)
-        self.collapsible = kwargs.get('collapsible', True)
-        self.deletable = kwargs.get('deletable', True)
-        self.show_title = kwargs.get('show_title', True)
-        self.title = kwargs.get('title', '')
-        self.title_url = kwargs.get('title_url', None)
-        self.css_classes = kwargs.get('css_classes', [])
-        self.pre_content = kwargs.get('pre_content')
-        self.post_content = kwargs.get('post_content')
-        self.template = kwargs.get('template', 'admin_tools/dashboard/module.html')
-        self.children = kwargs.get('children', [])
+
+    template = 'admin_tools/dashboard/module.html'
+    enabled = True
+    draggable = True
+    collapsible = True
+    deletable = True
+    show_title = True
+    title = ''
+    title_url = None
+    css_classes = None
+    pre_content = None
+    post_content = None
+    children = None
+
+    def __init__(self, title=None, **kwargs):
+        if title is not None:
+            self.title = title
+        for key in kwargs:
+            if hasattr(self.__class__, key):
+                setattr(self, key, kwargs[key])
+        self.children = self.children or []
+        self.css_classes = self.css_classes or []
 
     def init_with_context(self, context):
         """
             from admin_tools.dashboard import modules
 
             class HistoryDashboardModule(modules.LinkList):
+                title = 'History'
+
                 def init_with_context(self, context):
-                    self.title = 'History'
                     request = context['request']
                     # we use sessions to store the visited pages stack
                     history = request.session.get('history', [])
         of the following values: 'tabs' (default), 'accordion' or 'stacked'.
 
     Here's an example of modules group::
-        
+
         from admin_tools.dashboard import modules, Dashboard
 
         class MyDashboard(Dashboard):
     .. image:: images/dashboard_module_group.png
     """
 
-    def __init__(self, **kwargs):
-        super(Group, self).__init__(**kwargs)
-        self.template = kwargs.get('template',
-                                   'admin_tools/dashboard/modules/group.html')
-        self.display = kwargs.get('display', 'tabs')
-        
+    template = 'admin_tools/dashboard/modules/group.html'
+    display = 'tabs'
+
     def init_with_context(self, context):
         for module in self.children:
-            # to simplify the whole stuff, modules have some limitations, 
+            # to simplify the whole stuff, modules have some limitations,
             # they cannot be dragged, collapsed or closed
             module.collapsible = False
             module.draggable = False
         A string describing the link, it will be the ``title`` attribute of
         the html ``a`` tag.
 
+    Children can also be iterables (lists or tuples) of length 2, 3 or 4.
+
     Here's a small example of building a link list module::
 
         from admin_tools.dashboard import modules, Dashboard
                             'external': True,
                             'description': 'Python programming language rocks !',
                         },
-                        {
-                            'title': 'Django website',
-                            'url': 'http://www.djangoproject.com',
-                            'external': True
-                        },
-                        {
-                            'title': 'Some internal link',
-                            'url': '/some/internal/link/',
-                            'external': False
-                        },
+                        ['Django website', 'http://www.djangoproject.com', True],
+                        ['Some internal link', '/some/internal/link/'],
                     )
                 ))
 
     .. image:: images/linklist_dashboard_module.png
     """
 
-    def __init__(self, **kwargs):
-        super(LinkList, self).__init__(**kwargs)
-        self.title = kwargs.get('title', _('Links'))
-        self.template = kwargs.get('template',
-                                   'admin_tools/dashboard/modules/link_list.html')
-        self.layout = kwargs.get('layout', 'stacked')
+    title = _('Links')
+    template = 'admin_tools/dashboard/modules/link_list.html'
+    layout = 'stacked'
+
+    def init_with_context(self, context):
+        new_children = []
+        for link in self.children:
+            if isinstance(link, (tuple, list,)):
+                link_dict = {'title': link[0], 'url': link[1]}
+                if len(link) >= 3:
+                    link_dict['external'] = link[2]
+                if len(link) >= 4:
+                    link_dict['description'] = link[3]
+                new_children.append(link_dict)
+            else:
+                new_children.append(link)
+        self.children = new_children
 
 
 class AppList(DashboardModule, AppListElementMixin):
         the django.contrib.auth.Group model line will not be displayed.
     """
 
-    def __init__(self, **kwargs):
-        super(AppList, self).__init__(**kwargs)
-        self.title = kwargs.get('title', _('Applications'))
-        self.template = kwargs.get('template',
-                                   'admin_tools/dashboard/modules/app_list.html')
-        self.include_list = kwargs.get('include_list', [])
-        self.exclude_list = kwargs.get('exclude_list', [])
+    title = _('Applications')
+    template = 'admin_tools/dashboard/modules/app_list.html'
+    models = None
+    exclude = None
+    include_list = None
+    exclude_list = None
 
-        self.models = list(kwargs.get('models', []))
-        self.exclude = list(kwargs.get('exclude', []))
-
+    def __init__(self, title=None, **kwargs):
+        self.include_list = kwargs.pop('include_list', [])
+        self.exclude_list = kwargs.pop('exclude_list', [])
+        self.models = list(kwargs.pop('models', []))
+        self.exclude = list(kwargs.pop('exclude', []))
+        super(AppList, self).__init__(title, **kwargs)
 
     def init_with_context(self, context):
         items = self._visible_models(context['request'])
     Module that lists a set of models.
     As well as the :class:`~admin_tools.dashboard.modules.DashboardModule`
     properties, the :class:`~admin_tools.dashboard.modules.ModelList` takes
-    two extra keyword arguments:
+    two extra arguments:
 
-    ``include_list``
+    ``models``
         A list of models to include, only models whose name (e.g.
-        "blog.comments.Comment") starts with one of the strings (e.g. "blog")
+        "blog.comments.Comment") match one of the strings (e.g. "blog.*")
         in the include list will appear in the dashboard module.
 
-    ``exclude_list``
+    ``exclude``
         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.
+        "blog.comments.Comment" match 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::
 
                 Dashboard.__init__(self, **kwargs)
 
                 # will only list the django.contrib.auth models
-                self.children.append(modules.ModelList(
-                    title='Authentication',
-                    include_list=('django.contrib.auth',)
-                ))
+                self.children += [
+                    modules.ModelList('Authentication', ['django.contrib.auth.*',])
+                ]
 
     The screenshot of what this code produces:
 
         the django.contrib.auth.Group model line will not be displayed.
     """
 
-    def __init__(self, **kwargs):
-        super(ModelList, self).__init__(**kwargs)
-        self.title = kwargs.get('title', '')
-        self.template = kwargs.get('template',
-                                   'admin_tools/dashboard/modules/model_list.html')
-        self.include_list = kwargs.get('include_list', [])
-        self.exclude_list = kwargs.get('exclude_list', [])
-        self.models = list(kwargs.get('models', []))
-        self.exclude = list(kwargs.get('exclude', []))
+    template = 'admin_tools/dashboard/modules/model_list.html'
+
+    def __init__(self, title=None, models=None, exclude=None, **kwargs):
+        self.models = list(models or [])
+        self.exclude = list(exclude or [])
+        self.include_list = kwargs.pop('include_list', []) # deprecated
+        self.exclude_list = kwargs.pop('exclude_list', []) # deprecated
+        super(ModelList, self).__init__(title, **kwargs)
 
     def init_with_context(self, context):
         items = self._visible_models(context['request'])
 
     .. image:: images/recentactions_dashboard_module.png
     """
+    title = _('Recent Actions')
+    template = 'admin_tools/dashboard/modules/recent_actions.html'
+    limit = 10
 
-    def __init__(self, **kwargs):
-        super(RecentActions, self).__init__(**kwargs)
-        self.title = kwargs.get('title', _('Recent Actions'))
-        self.template = kwargs.get('template',
-                                   'admin_tools/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 __init__(self, title=None, limit=None,
+                 include_list=None, exclude_list=None, **kwargs):
+        self.include_list = include_list or []
+        self.exclude_list = exclude_list or []
+        self.limit = self.__class__.limit or limit
+        super(RecentActions, self).__init__(title, **kwargs)
 
     def init_with_context(self, context):
         from django.db.models import Q
 
     .. image:: images/feed_dashboard_module.png
     """
-    def __init__(self, **kwargs):
-        super(Feed, self).__init__(**kwargs)
-        self.title = kwargs.get('title', _('RSS Feed'))
-        self.template = kwargs.get('template', 'admin_tools/dashboard/modules/feed.html')
-        self.feed_url = kwargs.get('feed_url')
-        self.limit = kwargs.get('limit')
+
+    title = _('RSS Feed')
+    template = 'admin_tools/dashboard/modules/feed.html'
+    feed_url = None
+    limit = None
+
+    def __init__(self, title=None, feed_url=None, limit=None, **kwargs):
+        kwargs.update({'feed_url': feed_url, 'limit': limit})
+        super(Feed, self).__init__(title, **kwargs)
 
     def init_with_context(self, context):
         import datetime

File admin_tools/dashboard/registry.py

+#coding: utf-8
+
+class Registry(object):
+    """
+    Registry for application dashboards.
+    """
+    registry = {}
+
+    def register(cls, klass, app_name):
+        from admin_tools.dashboard.dashboards import Dashboard
+        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)

File admin_tools/dashboard/templates/admin_tools/dashboard/dashboard.txt

             deletable=False,
             collapsible=False,
             children=[
-                {
-                    'title': _('Return to site'),
-                    'url': '/',
-                },
-                {
-                    'title': _('Change password'),
-                    'url': reverse('admin:password_change'),
-                },
-                {
-                    'title': _('Log out'),
-                    'url': reverse('admin:logout')
-                },
+                [_('Return to site'), '/'],
+                [_('Change password'), reverse('admin:password_change')],
+                [_('Log out'), reverse('admin:logout')],
             ]
         ))
 

File admin_tools/dashboard/templatetags/admin_tools_dashboard_tags.py

 def admin_tools_render_dashboard(context, location='index', dashboard=None):
     """
     Template tag that renders the dashboard, it takes two optional arguments:
-    
+
     ``location``
         The location of the dashboard, it can be 'index' (for the admin index
         dashboard) or 'app_index' (for the app index dashboard), the default
     """
     Template tag that renders the dashboard css files, it takes two optional
     arguments:
-    
+
     ``location``
         The location of the dashboard, it can be 'index' (for the admin index
         dashboard) or 'app_index' (for the app index dashboard), the default

File admin_tools/dashboard/utils.py

 """
 Dashboard utilities.
 """
-
 from django.conf import settings
 from django.contrib import admin
-from django.core.exceptions import ImproperlyConfigured
 from django.utils.importlib import import_module
 from django.utils.text import capfirst
-from admin_tools.dashboard import Registry
-
+from admin_tools.dashboard.registry import Registry
 
 def get_dashboard(context, location):
     """
     dashboard_cls = getattr(
         settings,
         'ADMIN_TOOLS_INDEX_DASHBOARD',
-        'admin_tools.dashboard.DefaultIndexDashboard'
+        'admin_tools.dashboard.dashboards.DefaultIndexDashboard'
     )
     mod, inst = dashboard_cls.rsplit('.', 1)
     mod = import_module(mod)
     dashboard_cls = getattr(
         settings,
         'ADMIN_TOOLS_APP_INDEX_DASHBOARD',
-        'admin_tools.dashboard.DefaultAppIndexDashboard'
+        'admin_tools.dashboard.dashboards.DefaultAppIndexDashboard'
     )
     mod, inst = dashboard_cls.rsplit('.', 1)
     mod = import_module(mod)

File admin_tools/menu/items.py

         the ``MenuItem`` class.
     """
 
-    def __init__(self, **kwargs):
-        """
-        ``MenuItem`` constructor.
-        """
-        self.title = kwargs.get('title', 'Untitled menu item')
-        self.url = kwargs.get('url', '#')
-        self.css_classes = kwargs.get('css_classes', [])
-        self.accesskey = kwargs.get('accesskey')
-        self.description = kwargs.get('description')
-        self.enabled = kwargs.get('enabled', True)
-        self.template = kwargs.get('template', 'admin_tools/menu/item.html')
-        self.children = kwargs.get('children', [])
+    title = 'Untitled menu item'
+    url = '#'
+    css_classes = None
+    accesskey = None
+    description = None
+    enabled = True
+    template = 'admin_tools/menu/item.html'
+    children = None
+
+    def __init__(self, title=None, url=None, **kwargs):
+
+        if title is not None:
+            self.title = title
+
+        if url is not None:
+            self.url = url
+
+        for key in kwargs:
+            if hasattr(self.__class__, key):
+                setattr(self, key, kwargs[key])
+        self.children = self.children or []
+        self.css_classes = self.css_classes or []
 
     def init_with_context(self, context):
         """
             from admin_tools.menu.items import MenuItem
 
             class HistoryMenuItem(MenuItem):
+                title = 'History'
+
                 def init_with_context(self, context):
-                    self.title = 'History'
                     request = context['request']
                     # we use sessions to store the visited pages stack
                     history = request.session.get('history', [])
     def is_empty(self):
         """
         Helper method that returns ``True`` if the menu item is empty.
-        This method always returns ``False`` for basic items, but can return 
+        This method always returns ``False`` for basic items, but can return
         ``True`` if the item is an AppList.
         """
         return False
         displayed in the menu.
     """
 
-    def __init__(self, **kwargs):
+    def __init__(self, title=None, **kwargs):
         """
         ``AppListMenuItem`` constructor.
         """
-        super(AppList, self).__init__(**kwargs)
-        self.include_list = kwargs.get('include_list', [])
-        self.exclude_list = kwargs.get('exclude_list', [])
-        self.models = list(kwargs.get('models', []))
-        self.exclude = list(kwargs.get('exclude', []))
+        self.include_list = kwargs.pop('include_list', [])
+        self.exclude_list = kwargs.pop('exclude_list', [])
+        self.models = list(kwargs.pop('models', []))
+        self.exclude = list(kwargs.pop('exclude', []))
+        super(AppList, self).__init__(title, **kwargs)
 
 
     def init_with_context(self, context):
 
     def is_empty(self):
         """
-        Helper method that returns ``True`` if the applist menu item has no 
+        Helper method that returns ``True`` if the applist menu item has no
         children.
 
         >>> from admin_tools.menu.items import MenuItem, AppList
         class MyMenu(Menu):
             def __init__(self, **kwargs):
                 super(MyMenu, self).__init__(**kwargs)
-                self.children.append(items.Bookmarks(title='My bookmarks'))
+                self.children.append(items.Bookmarks('My bookmarks'))
 
     """
+    title = _('Bookmarks')
 
-    def __init__(self, **kwargs):
-        super(Bookmarks, self).__init__(**kwargs)
-        self.title = kwargs.get('title', _('Bookmarks'))
+    def __init__(self, title=None, **kwargs):
+        super(Bookmarks, self).__init__(title, **kwargs)
         if 'bookmark' not in self.css_classes:
             self.css_classes.append('bookmark')
 
         documentation from :class:`~admin_tools.menu.items.MenuItem` class.
         """
         from admin_tools.menu.models import Bookmark
+
         for b in Bookmark.objects.filter(user=context['request'].user):
-            self.children.append(MenuItem(
-                url=b.url,
-                title=mark_safe(b.title)
-            ))
+            self.children.append(MenuItem(mark_safe(b.title), b.url))
+
         if not len(self.children):
             self.enabled = False
 

File admin_tools/menu/menus.py

         class MyMenu(Menu):
             def __init__(self, **kwargs):
                 super(MyMenu, self).__init__(**kwargs)
-                self.children.append(
-                    items.MenuItem(title='Home', url=reverse('admin:index'))
-                )
-                self.children.append(
-                    items.AppList(title='Applications')
-                )
-                self.children.append(
-                    items.MenuItem(
-                        title='Multi level menu item',
+                self.children += [
+                    items.MenuItem('Home', reverse('admin:index')),
+                    items.AppList('Applications'),
+                    items.MenuItem('Multi level menu item',
                         children=[
-                            items.MenuItem(title='Child 1', url='/foo/'),
-                            items.MenuItem(title='Child 2', url='/bar/'),
+                            items.MenuItem('Child 1', '/foo/'),
+                            items.MenuItem('Child 2', '/bar/'),
                         ]
                     ),
-                )
+                ]
 
     Below is a screenshot of the resulting menu:
 
     .. image:: images/menu_example.png
     """
+    template = 'admin_tools/menu/menu.html'
+    children = None
 
     class Media:
         css = ()
         js  = ()
 
     def __init__(self, **kwargs):
-        """
-        Menu constructor.
-        """
-        self.template = kwargs.get('template', 'admin_tools/menu/menu.html')
+        for key in kwargs:
+            if hasattr(self.__class__, key):
+                setattr(self, key, kwargs[key])
         self.children = kwargs.get('children', [])
 
     def init_with_context(self, context):
     """
     def __init__(self, **kwargs):
         super(DefaultMenu, self).__init__(**kwargs)
-        self.children.append(items.MenuItem(
-            title=_('Dashboard'),
-            url=reverse('admin:index')
-        ))
-        self.children.append(items.Bookmarks())
-        self.children.append(items.AppList(
-            title=_('Applications'),
-            exclude_list=('django.contrib',)
-        ))
-        self.children.append(items.AppList(
-            title=_('Administration'),
-            include_list=('django.contrib',)
-        ))
+
+        self.children += [
+            items.MenuItem(_('Dashboard'), reverse('admin:index')),
+            items.Bookmarks(),
+            items.AppList(
+                _('Applications'),
+                exclude_list=('django.contrib',)
+            ),
+            items.AppList(
+                _('Administration'),
+                include_list=('django.contrib',)
+            )
+        ]

File admin_tools/tests.py

         self.assertDeprecated(models.FeedDashboardModule)
 
     def test_dashboard_new(self):
-        from admin_tools import dashboard
+        from admin_tools.dashboard import dashboards
 
-        self.assertNotDeprecated(dashboard.Dashboard)
-        self.assertNotDeprecated(dashboard.DefaultIndexDashboard)
-        self.assertNotDeprecated(dashboard.DefaultAppIndexDashboard, '', [])
-        self.assertNotDeprecated(dashboard.AppIndexDashboard, '', [])
+        self.assertNotDeprecated(dashboards.Dashboard)
+        self.assertNotDeprecated(dashboards.DefaultIndexDashboard)
+        self.assertNotDeprecated(dashboards.DefaultAppIndexDashboard, '', [])
+        self.assertNotDeprecated(dashboards.AppIndexDashboard, '', [])
 
         from admin_tools.dashboard import modules
         self.assertNotDeprecated(modules.DashboardModule)
         self.assertNotDeprecated(modules.LinkList)
         self.assertNotDeprecated(modules.Feed)
 
-
     def test_menu(self):
         from admin_tools.menu import models
         self.assertDeprecated(models.Menu)

File test_proj/dashboard.py

 
         # append a link list module for "quick links"
         self.children.append(modules.LinkList(
-            title=_('Quick links'),
+            _('Quick links'),
             layout='inline',
             draggable=False,
             deletable=False,
             collapsible=False,
             children=[
-                {
-                    'title': _('Return to site'),
-                    'url': '/',
-                },
-                {
-                    'title': _('Change password'),
-                    'url': reverse('admin:password_change'),
-                },
-                {
-                    'title': _('Log out'),
-                    'url': reverse('admin:logout')
-                },
+                [_('Return to site'), '/'],
+                [_('Change password'), reverse('admin:password_change')],
+                [_('Log out'), reverse('admin:logout')],
             ]
         ))
 
         # append an app list module for "Applications"
         self.children.append(modules.AppList(
-            title=_('Applications'),
+            _('Applications'),
             exclude_list=('django.contrib',),
         ))
 
         # append an app list module for "Administration"
         self.children.append(modules.AppList(
-            title=_('Administration'),
+            _('Administration'),
             include_list=('django.contrib',),
         ))
 
         self.children.append(modules.ModelList(
-            title='Test1',
-            models = ['django.contrib.auth.*', '*.Site', '*.Foo'],
-            exclude = ['django.contrib.auth.models.User', 'test_app.*']
+            'Test1',
+            ['django.contrib.auth.*', '*.Site', '*.Foo'],
+            ['django.contrib.auth.models.User', 'test_app.*']
         ))
 
         # append a recent actions module
-        self.children.append(modules.RecentActions(
-            title=_('Recent Actions'),
-            limit=5
-        ))
+        self.children.append(
+             modules.RecentActions(_('Recent Actions'), 5)
+        )
 
         # append another link list module for "support".
         self.children.append(modules.LinkList(
-            title=_('Support'),
+            _('Support'),
             children=[
                 {
                     'title': _('Django documentation'),
     """
     Custom app index dashboard for test_proj.
     """
+
+    # we disable title because its redundant with the model list module
+    title = ''
+
     def __init__(self, *args, **kwargs):
         AppIndexDashboard.__init__(self, *args, **kwargs)
 
-        # we disable title because its redundant with the model list module
-        self.title = ''
-
-        # append a model list module
-        self.children.append(modules.ModelList(
-            title=self.app_title,
-            include_list=self.models,
-        ))
-
-        # append a recent actions module
-        self.children.append(modules.RecentActions(
-            title=_('Recent Actions'),
-            include_list=self.get_app_content_types(),
-        ))
+        self.children += [
+            modules.ModelList(self.app_title, include_list=self.models),
+            modules.RecentActions(include_list=self.get_app_content_types()),
+        ]
 
     def init_with_context(self, context):
         """