2016-11-21 19:35:17 +00:00
|
|
|
from functools import wraps, partial, update_wrapper
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2016-02-11 14:24:09 +00:00
|
|
|
from django.contrib import messages
|
2014-05-08 16:59:35 +00:00
|
|
|
from django.contrib.admin import helpers
|
2016-02-11 14:24:09 +00:00
|
|
|
from django.core.exceptions import ValidationError
|
2014-09-18 15:07:39 +00:00
|
|
|
from django.template.response import TemplateResponse
|
2014-05-08 16:59:35 +00:00
|
|
|
from django.utils.decorators import available_attrs
|
|
|
|
from django.utils.encoding import force_text
|
2014-09-18 15:07:39 +00:00
|
|
|
from django.utils.html import format_html
|
|
|
|
from django.utils.text import capfirst
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
|
2014-07-24 09:53:34 +00:00
|
|
|
def admin_field(method):
|
2014-07-24 15:43:23 +00:00
|
|
|
""" Wraps a function to be used as a ModelAdmin method field """
|
2014-07-24 09:53:34 +00:00
|
|
|
def admin_field_wrapper(*args, **kwargs):
|
|
|
|
""" utility function for creating admin links """
|
2016-02-11 14:24:09 +00:00
|
|
|
kwargs['field'] = args[0] if args else '__str__'
|
2014-07-24 09:53:34 +00:00
|
|
|
kwargs['order'] = kwargs.get('order', kwargs['field'])
|
|
|
|
kwargs['popup'] = kwargs.get('popup', False)
|
2014-10-20 19:22:18 +00:00
|
|
|
# TODO get field verbose name
|
2014-09-05 14:27:30 +00:00
|
|
|
kwargs['short_description'] = kwargs.get('short_description',
|
2014-07-24 09:53:34 +00:00
|
|
|
kwargs['field'].split('__')[-1].replace('_', ' ').capitalize())
|
|
|
|
admin_method = partial(method, **kwargs)
|
2016-11-21 19:35:17 +00:00
|
|
|
admin_method = update_wrapper(admin_method, method)
|
2014-09-05 14:27:30 +00:00
|
|
|
admin_method.short_description = kwargs['short_description']
|
2014-07-24 09:53:34 +00:00
|
|
|
admin_method.allow_tags = True
|
|
|
|
admin_method.admin_order_field = kwargs['order']
|
|
|
|
return admin_method
|
|
|
|
return admin_field_wrapper
|
|
|
|
|
|
|
|
|
2014-09-18 15:07:39 +00:00
|
|
|
def format_display_objects(modeladmin, request, queryset):
|
|
|
|
from .utils import change_url
|
|
|
|
opts = modeladmin.model._meta
|
|
|
|
objects = []
|
|
|
|
for obj in queryset:
|
|
|
|
objects.append(format_html('{0}: <a href="{1}">{2}</a>',
|
|
|
|
capfirst(opts.verbose_name), change_url(obj), obj)
|
|
|
|
)
|
|
|
|
return objects
|
|
|
|
|
|
|
|
|
2016-02-11 14:24:09 +00:00
|
|
|
def action_with_confirmation(action_name=None, extra_context=None, validator=None,
|
2014-07-09 16:17:43 +00:00
|
|
|
template='admin/orchestra/generic_confirmation.html'):
|
2014-05-08 16:59:35 +00:00
|
|
|
"""
|
|
|
|
Generic pattern for actions that needs confirmation step
|
|
|
|
If custom template is provided the form must contain:
|
|
|
|
<input type="hidden" name="post" value="generic_confirmation" />
|
|
|
|
"""
|
2014-09-18 15:07:39 +00:00
|
|
|
|
2016-02-11 14:24:09 +00:00
|
|
|
def decorator(func, extra_context=extra_context, template=template, action_name=action_name, validatior=validator):
|
2014-05-08 16:59:35 +00:00
|
|
|
@wraps(func, assigned=available_attrs(func))
|
2016-02-11 14:24:09 +00:00
|
|
|
def inner(modeladmin, request, queryset, action_name=action_name, extra_context=extra_context, validator=validator):
|
|
|
|
if validator is not None:
|
|
|
|
try:
|
|
|
|
validator(queryset)
|
|
|
|
except ValidationError as e:
|
|
|
|
messages.error(request, '<br>'.join(e))
|
|
|
|
return
|
2014-05-08 16:59:35 +00:00
|
|
|
# The user has already confirmed the action.
|
2014-09-18 15:07:39 +00:00
|
|
|
if request.POST.get('post') == 'generic_confirmation':
|
2014-05-08 16:59:35 +00:00
|
|
|
stay = func(modeladmin, request, queryset)
|
|
|
|
if not stay:
|
|
|
|
return
|
2014-07-24 09:53:34 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
opts = modeladmin.model._meta
|
|
|
|
app_label = opts.app_label
|
|
|
|
action_value = func.__name__
|
2014-07-24 09:53:34 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
if len(queryset) == 1:
|
|
|
|
objects_name = force_text(opts.verbose_name)
|
2014-09-26 15:05:20 +00:00
|
|
|
obj = queryset.get()
|
2014-05-08 16:59:35 +00:00
|
|
|
else:
|
|
|
|
objects_name = force_text(opts.verbose_name_plural)
|
2014-09-26 15:05:20 +00:00
|
|
|
obj = None
|
2014-09-16 17:14:24 +00:00
|
|
|
if not action_name:
|
|
|
|
action_name = func.__name__
|
2014-05-08 16:59:35 +00:00
|
|
|
context = {
|
2014-09-18 15:07:39 +00:00
|
|
|
'title': _("Are you sure?"),
|
|
|
|
'content_message': _("Are you sure you want to {action} the selected {item}?").format(
|
2015-07-09 10:44:22 +00:00
|
|
|
action=action_name, item=objects_name),
|
2014-09-18 15:07:39 +00:00
|
|
|
'action_name': action_name.capitalize(),
|
|
|
|
'action_value': action_value,
|
2014-05-08 16:59:35 +00:00
|
|
|
'queryset': queryset,
|
2014-09-18 15:07:39 +00:00
|
|
|
'opts': opts,
|
2014-09-26 15:05:20 +00:00
|
|
|
'obj': obj,
|
2014-09-18 15:07:39 +00:00
|
|
|
'app_label': app_label,
|
2014-05-08 16:59:35 +00:00
|
|
|
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
|
|
|
|
}
|
2014-07-24 09:53:34 +00:00
|
|
|
|
2014-09-18 15:07:39 +00:00
|
|
|
if callable(extra_context):
|
|
|
|
extra_context = extra_context(modeladmin, request, queryset)
|
2016-02-11 14:24:09 +00:00
|
|
|
context.update(extra_context or {})
|
2014-09-18 15:07:39 +00:00
|
|
|
if 'display_objects' not in context:
|
|
|
|
# Compute it only when necessary
|
|
|
|
context['display_objects'] = format_display_objects(modeladmin, request, queryset)
|
2014-07-24 09:53:34 +00:00
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
# Display the confirmation page
|
2016-10-22 07:23:45 +00:00
|
|
|
return TemplateResponse(request, template, context)
|
2014-05-08 16:59:35 +00:00
|
|
|
return inner
|
|
|
|
return decorator
|