I decided to go with a custom field and override post(). Would appreciate comments/edits if there's a better way.
forms.py
import uuid
from django.core.exceptions import ValidationError
MAX_UUIDS = 10
class UUIDArrayField(forms.Field):
""" Custom field representing an array of up to MAX_UUIDS uuid4 strings """
def clean(self, value):
if type(value) != type([]):
raise ValidationError(self.error_messages['not_a_list'])
if len(value) > MAX_UUIDS:
raise ValidationError(self.error_messages['too_many_values'])
try:
for v in value:
print(v)
uuid.UUID(v, version=4) # ValueError if not a valid uuid4
return value
except:
raise ValidationError(self.error_messages['invalid_uuid'])
class ObjectMultiDeleteForm(forms.Form):
""" form to delete multiple products """
uuids = UUIDArrayField(
error_messages = {
'not_a_list': _("A data type other than list was supplied."),
'too_many_values': _("The list of values exceeds the maximum allowed."),
'invalid_uuid': _("An invalid identifier was specified."),
})
views.py
from django.shortcuts import redirect
class ObjectMultiDelete(FormView):
""" Deletes object instances from a list of their uuids """
http_method_names = ['post',] #only accept POST requests
success_url = reverse_lazy("objectlist")
success_message = "%(message)s"
form_class = ProductMultiDeleteForm
def dispatch(self, request, *args, **kwargs):
#access control goes here
return super(ObjectMultiDelete, self).dispatch(request, *args, **kwargs)
def get_success_message(self, cleaned_data):
return self.success_message % dict(
message = _("The specified objects were successfully deleted."),
)
def post(self, request, *args, **kwargs):
post_data = request.POST.copy() #request.POST is immutable
#because you can't name a form field 'uuids[]', but that's what you get when posting an array
post_data['uuids'] = post_data.pop('uuids[]')
form = ObjectMultiDeleteForm()
form.data = post_data #bind form
form.is_bound = True
if form.is_valid():
objects = Object.objects.filter(access_control_here)\
.filter(uuid__in=form.cleaned_data['uuids'])
objects.delete()
return redirect(self.success_url)
else:
#handle invalid form how you want