Mix of Python and Django utility functions, classed etc.
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.

173 lines
7.0 KiB

6 years ago
from django import forms
from django.contrib import admin
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
6 years ago
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import ngettext, gettext_lazy as _
6 years ago
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
6 years ago
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}