Commits

Mikhail Korobov committed ca4395a

Support for 'models' and 'exclude' parameters for dashboard.modules.ModelList, dashboard.modules.AppList, menu.items.AppList

  • Participants
  • Parent commits 48d2147

Comments (0)

Files changed (4)

File admin_tools/dashboard/modules.py

-from django.contrib import admin
 from django.utils.text import capfirst
 from django.core.urlresolvers import reverse
 from django.contrib.contenttypes.models import ContentType
         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', []))
+
+
     def init_with_context(self, context):
-        request = context['request']
+        items = self._visible_models(context['request'])
         apps = {}
-        for model, model_admin in admin.site._registry.items():
-            perms = self._check_perms(request, model, model_admin)
-            if not perms or ('add' not in perms and 'change' not in perms):
-                continue
+        for model, perms in items:
             app_label = model._meta.app_label
             if app_label not in apps:
                 apps[app_label] = {
                                    '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', []))
 
     def init_with_context(self, context):
-        request = context['request']
-        for model, model_admin in admin.site._registry.items():
-            perms = self._check_perms(request, model, model_admin)
-            if not perms:
-                continue
+        items = self._visible_models(context['request'])
+        if not items:
+            return
+        for model, perms in items:
             model_dict = {}
             model_dict['title'] = capfirst(model._meta.verbose_name_plural)
             if perms['change']:
                 model_dict['add_url'] = self._get_admin_add_url(model)
             self.children.append(model_dict)
 
-        # sort model list alphabetically
-        self.children.sort(lambda x, y: cmp(x['title'], y['title']))
-
 
 class RecentActions(DashboardModule):
     """

File admin_tools/menu/items.py

-from django.contrib import admin
 from django.core.urlresolvers import reverse
 from django.utils.safestring import mark_safe
 from django.utils.text import capfirst
         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', []))
+
 
     def init_with_context(self, context):
         """
         Please refer to the :meth:`~admin_tools.menu.items.MenuItem.init_with_context`
         documentation from :class:`~admin_tools.menu.items.MenuItem` class.
         """
-        request = context['request']
+        items = self._visible_models(context['request'])
         apps = {}
-        for model, model_admin in admin.site._registry.items():
-            perms = self._check_perms(request, model, model_admin)
-            if not perms or not perms['change']:
+        for model, perms in items:
+            if not perms['change']:
                 continue
             app_label = model._meta.app_label
             if app_label not in apps:

File admin_tools/utils.py

 """
 Admin ui common utilities.
 """
+from django.conf import settings
+from django.contrib import admin
+from django.core.urlresolvers import reverse
+from fnmatch import fnmatch
 
-from django.conf import settings
-from django.core.urlresolvers import reverse
+def get_avail_models(request):
+    """ Returns (model, perm,) for all models user can possibly see """
+    items = []
+    for model, model_admin in admin.site._registry.items():
+        perms = model_admin.get_model_perms(request)
+        if True not in perms.values():
+            continue
+        items.append((model, perms,))
+    return items
+
+def filter_models(request, models, exclude):
+    """ Returns (model, perm,) for all models that match
+        models/exclude patterns and are visible by current user.
+    """
+    items = get_avail_models(request)
+    included = []
+    full_name = lambda model: '%s.%s' % (model.__module__, model.__name__)
+
+    # I beleive that that implemented
+    # O(len(patterns)*len(matched_patterns)*len(all_models))
+    # algorythm is fine for model lists because they are small and admin
+    # performance is not a bottleneck. If it is not the case then the code
+    # should be optimized.
+
+    for pattern in models:
+        for item in items:
+            model, perms = item
+            if fnmatch(full_name(model), pattern) and item not in included:
+                included.append(item)
+
+    result = included[:]
+    for pattern in exclude:
+        for item in included:
+            model, perms = item
+            if fnmatch(full_name(model), pattern):
+                result.remove(item)
+    return result
+
 
 class AppListElementMixin(object):
     """
     Mixin class used by both the AppListDashboardModule and the
     AppListMenuItem (to honor the DRY concept).
     """
-    def _check_perms(self, request, model, model_admin):
-        """
-        Checks that the current user can view the given model in the admin.
-        """
-        mod = '%s.%s' % (model.__module__, model.__name__)
 
-        # check that the app is not in the exclude list
-        for pattern in self.exclude_list:
-            if mod.startswith(pattern):
-                return False
+    def _visible_models(self, request):
+        # compatibility layer: generate models/exclude patterns
+        # from include_list/exclude_list args
+        included = self.models[:]
+        included.extend([elem+"*" for elem in self.include_list])
 
-        # check that the app is in the app list (if not empty)
-        if len(self.include_list):
-            found = False
-            for pattern in self.include_list:
-                if mod.startswith(pattern):
-                    found = True
-            if not found:
-                return False
+        excluded = self.exclude[:]
+        excluded.extend([elem+"*" for elem in self.exclude_list])
+        if self.exclude_list and not included:
+            included = ["*"]
+        return filter_models(request, included, excluded)
 
-        # check that the user has module perms
-        if not request.user.has_module_perms(model._meta.app_label):
-            return False
-
-        # check whether user has any perm for this module
-        perms = model_admin.get_model_perms(request)
-        if True not in perms.values():
-            return False
-        return perms
 
     def _get_admin_change_url(self, model):
         """

File test_proj/dashboard.py

             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.*']
+        ))
+
         # append a recent actions module
         self.children.append(modules.RecentActions(
             title=_('Recent Actions'),