You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
7.0 KiB
172 lines
7.0 KiB
from django import forms |
|
from django.contrib import admin |
|
from django.contrib.admin.widgets import ForeignKeyRawIdWidget |
|
from django.http import HttpResponseRedirect |
|
from django.shortcuts import render |
|
from django.utils.translation import ngettext, gettext_lazy as _ |
|
|
|
|
|
class AdminActionBase: |
|
action_name = None |
|
options_template_name = 'admin/action_forms/admin_action_base.html' |
|
title = None |
|
queryset_action_label = None |
|
action_button_label = None |
|
|
|
def __init__(self, action_name=None): |
|
if action_name: |
|
self.action_name = action_name |
|
|
|
def apply(self, queryset, form): |
|
raise NotImplementedError |
|
|
|
def get_message(self, count): |
|
raise NotImplementedError |
|
|
|
def get_failure_message(self, count, failure_count): |
|
raise NotImplementedError |
|
|
|
class BaseForm(forms.Form): |
|
_selected_action = forms.CharField(widget=forms.MultipleHiddenInput) |
|
|
|
def get_form_class(self, modeladmin, request, queryset): |
|
""" |
|
Example: |
|
|
|
class CustomForm(BaseForm) |
|
chosen_target = forms.ModelChoiceField( |
|
label=_("Choose target itembundle"), |
|
queryset=ItemBundle.objects.exclude(pk__in=queryset), |
|
widget=ForeignKeyRawIdWidget(modeladmin.model._meta.get_field('parent').rel, modeladmin.admin_site), |
|
empty_label=_("Root level"), required=False) |
|
return CustomForm |
|
""" |
|
raise NotImplementedError |
|
|
|
def __call__(self, modeladmin, request, queryset): |
|
form_class = self.get_form_class(modeladmin, request, queryset) |
|
|
|
form = None |
|
if 'apply' in request.POST: |
|
form = form_class(request.POST) |
|
if form.is_valid(): |
|
queryset_count = queryset.count() |
|
count = self.apply(queryset, form) |
|
failure_count = queryset_count - count |
|
if failure_count > 0: |
|
message = self.get_failure_message(form, count, failure_count) |
|
else: |
|
message = self.get_message(form, count) |
|
modeladmin.message_user(request, message) |
|
return HttpResponseRedirect(request.get_full_path()) |
|
|
|
if 'cancel' in request.POST: |
|
return HttpResponseRedirect(request.get_full_path()) |
|
|
|
if not form: |
|
form = form_class(initial={ |
|
'_selected_action': request.POST.getlist( |
|
admin.ACTION_CHECKBOX_NAME), |
|
}) |
|
|
|
return render(request, self.options_template_name, context={ |
|
'action_name': self.action_name, |
|
'title': self.title, |
|
'queryset_action_label': self.queryset_action_label, |
|
'action_button_label': self.action_button_label, |
|
'queryset': queryset, |
|
'action_form': form, |
|
'opts': modeladmin.model._meta, |
|
}) |
|
|
|
|
|
class TargetActionBase(AdminActionBase): |
|
target_model = None |
|
related_field_name = None |
|
|
|
def get_form_class(self, modeladmin, request, queryset): |
|
class ChooseTargetForm(AdminActionBase.BaseForm): |
|
chosen_target = forms.ModelChoiceField( |
|
label=_("Choose {}".format(self.target_model._meta.verbose_name)), |
|
queryset=self.target_model.objects.exclude(pk__in=queryset), |
|
widget=ForeignKeyRawIdWidget( |
|
modeladmin.model._meta.get_field(self.related_field_name).rel, |
|
modeladmin.admin_site |
|
), |
|
) |
|
return ChooseTargetForm |
|
|
|
def get_target(self, form): |
|
return form.cleaned_data['chosen_target'] |
|
|
|
def get_message(self, form, count): |
|
chosen_target = form.cleaned_data['chosen_target'] |
|
target_name = chosen_target.name |
|
return ngettext( |
|
'Successfully added %(count)d %(verbose_name)s to %(target)s.', |
|
'Successfully added %(count)d %(verbose_name_plural)s to %(target)s.', |
|
count) % { |
|
'count': count, |
|
'verbose_name': self.target_model._meta.verbose_name, |
|
'verbose_name_plural': self.target_model._meta.verbose_name_plural, |
|
'target': target_name} |
|
|
|
def get_failure_message(self, form, count, failure_count): |
|
chosen_target = form.cleaned_data['chosen_target'] |
|
target_name = chosen_target.name |
|
return ngettext( |
|
'Adding %(count)d %(verbose_name)s to %(target)s, %(failure_count)s failed or skipped.', |
|
'Adding %(count)d %(verbose_name_plural)s to %(target)s, %(failure_count)s failed or skipped.', |
|
count) % { |
|
'count': count, |
|
'verbose_name': self.target_model._meta.verbose_name, |
|
'verbose_name_plural': self.target_model._meta.verbose_name_plural, |
|
'target': target_name, |
|
'failure_count': failure_count} |
|
|
|
|
|
class ChangeForeignKeyAction(AdminActionBase): |
|
# Subclass:: |
|
# action_name = 'change_fieldname_action' |
|
# field_name_label = _("<field name>") |
|
# title = _("Change <field name>") |
|
# queryset_action_label = _("For the following items the <field name> will be changed:") |
|
# action_button_label = _("Change <field name>") |
|
|
|
def apply(self, queryset, form): |
|
raise NotImplementedError("apply must be implemented by the subclass.") |
|
# Subclass:: |
|
# new_value = form.cleaned_data['new_value'] |
|
# return change_fieldname_state(queryset, new_value) |
|
|
|
def get_value_choices_queryset(self, modeladmin, request, queryset): |
|
raise NotImplementedError("get_value_choices_queryset must be implemented by the subclass.") |
|
|
|
def get_form_class(self, modeladmin, request, queryset): |
|
class ChooseValueForm(AdminActionBase.BaseForm): |
|
new_value = forms.ModelChoiceField( |
|
label=_("Choose %(field_name)s" % {'field_name': self.field_name_label}), |
|
queryset=self.get_value_choices_queryset(modeladmin, request, queryset), |
|
required=True) |
|
return ChooseValueForm |
|
|
|
def get_message(self, form, count): |
|
new_value = form.cleaned_data['new_value'] |
|
return ngettext( |
|
'Successfully changed %(field_name)s of %(count)d item to %(new_value)s.', |
|
'Successfully changed %(field_name)s of %(count)d items to %(new_value)s.', |
|
count) % { |
|
'field_name': self.field_name_label, |
|
'count': count, |
|
'new_value': new_value} |
|
|
|
def get_failure_message(self, form, count, failure_count): |
|
new_value = form.cleaned_data['new_value'] |
|
return ngettext( |
|
'Successfully changed %(field_name)s of %(count)d item to %(new_value)s, %(failure_count)s failed or skipped.', |
|
'Successfully changed %(field_name)s of %(count)d items to %(new_value)s, %(failure_count)s failed or skipped.', |
|
count) % { |
|
'field_name': self.field_name_label, |
|
'count': count, |
|
'new_value': new_value, |
|
'failure_count': failure_count}
|
|
|