debian-django-admin-tools/admin_tools/utils.py

168 lines
5.4 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()))
def get_media_url():
"""
Returns the django admin tools media URL.
"""
media_url = getattr(settings, 'ADMIN_TOOLS_MEDIA_URL', None)
if media_url is None:
media_url = getattr(settings, 'STATIC_URL', None)
if media_url is None:
media_url = getattr(settings, 'MEDIA_URL')
return media_url.rstrip('/')