157 lines
5.1 KiB
Python
157 lines
5.1 KiB
Python
"""
|
|
Admin ui common utilities.
|
|
"""
|
|
from fnmatch import fnmatch
|
|
|
|
from django.conf import settings
|
|
from django.contrib import admin
|
|
from django.core.urlresolvers import reverse
|
|
try:
|
|
from importlib import import_module
|
|
except ImportError:
|
|
# Django < 1.9 and Python < 2.7
|
|
from django.utils.importlib import import_module
|
|
import warnings
|
|
|
|
def uniquify(value, seen_values):
|
|
""" Adds value to seen_values set and ensures it is unique """
|
|
id = 1
|
|
new_value = value
|
|
while new_value in seen_values:
|
|
new_value = "%s%s" % (value, id)
|
|
id += 1
|
|
seen_values.add(new_value)
|
|
return new_value
|
|
|
|
def get_admin_site(context=None, request=None):
|
|
dashboard_cls = getattr(
|
|
settings,
|
|
'ADMIN_TOOLS_INDEX_DASHBOARD',
|
|
'admin_tools.dashboard.dashboards.DefaultIndexDashboard'
|
|
)
|
|
|
|
if isinstance(dashboard_cls, dict):
|
|
if context:
|
|
request = context.get('request')
|
|
curr_url = request.path
|
|
for key in dashboard_cls:
|
|
mod, inst = key.rsplit('.', 1)
|
|
mod = import_module(mod)
|
|
admin_site = getattr(mod, inst)
|
|
admin_url = reverse('%s:index' % admin_site.name)
|
|
if curr_url.startswith(admin_url):
|
|
return admin_site
|
|
else:
|
|
return admin.site
|
|
raise ValueError('Admin site matching "%s" not found' % dashboard_cls)
|
|
|
|
def get_admin_site_name(context):
|
|
return get_admin_site(context).name
|
|
|
|
def get_avail_models(request):
|
|
""" Returns (model, perm,) for all models user can possibly see """
|
|
items = []
|
|
admin_site = get_admin_site(request=request)
|
|
|
|
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.
|
|
|
|
if len(models) == 0:
|
|
included = items
|
|
else:
|
|
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):
|
|
try:
|
|
result.remove(item)
|
|
except ValueError: # if the item was already removed skip
|
|
pass
|
|
return result
|
|
|
|
|
|
class AppListElementMixin(object):
|
|
"""
|
|
Mixin class used by both the AppListDashboardModule and the
|
|
AppListMenuItem (to honor the DRY concept).
|
|
"""
|
|
|
|
def _visible_models(self, request):
|
|
# compatibility layer: generate models/exclude patterns
|
|
# from include_list/exclude_list args
|
|
|
|
if self.include_list:
|
|
warnings.warn(
|
|
"`include_list` is deprecated for ModelList and AppList and "
|
|
"will be removed in future releases. Please use `models` instead.",
|
|
DeprecationWarning
|
|
)
|
|
|
|
if self.exclude_list:
|
|
warnings.warn(
|
|
"`exclude_list` is deprecated for ModelList and AppList and "
|
|
"will be removed in future releases. Please use `exclude` instead.",
|
|
DeprecationWarning
|
|
)
|
|
|
|
included = self.models[:]
|
|
included.extend([elem+"*" for elem in self.include_list])
|
|
|
|
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)
|
|
|
|
def _get_admin_app_list_url(self, model, context):
|
|
"""
|
|
Returns the admin change url.
|
|
"""
|
|
app_label = model._meta.app_label
|
|
return reverse('%s:app_list' % get_admin_site_name(context),
|
|
args=(app_label,))
|
|
|
|
def _get_admin_change_url(self, model, context):
|
|
"""
|
|
Returns the admin change url.
|
|
"""
|
|
app_label = model._meta.app_label
|
|
return reverse('%s:%s_%s_changelist' % (get_admin_site_name(context),
|
|
app_label,
|
|
model.__name__.lower()))
|
|
|
|
def _get_admin_add_url(self, model, context):
|
|
"""
|
|
Returns the admin add url.
|
|
"""
|
|
app_label = model._meta.app_label
|
|
return reverse('%s:%s_%s_add' % (get_admin_site_name(context),
|
|
app_label,
|
|
model.__name__.lower()))
|