[Fixed]-Which django form field type should I use for an array of values?

1👍

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
👤Escher

0👍

In that case you’re probably be best of with writing a small model that you can include at another place:

class UUIDItem(models.Model):
    request = models.PositiveIntegerField()
    uuid = models.UUID()

which you can easily put in relation with another model:

class UUIDContainer(models.Model):
    request = AutoField()

    @classmethod
    def add(self, uuid):
        if isinstance(uuid, list):
            for id in uuids:
                UUIDItem.objects.filter(request=self.request, uuid=id).create()
        else:
            UUIDItem.objects.filter(request=self.request, uuid=uuid).create()

    uuids = models.ForeignKey(
        UUIDRequest,
        on_delete=model.CASCADE,
        limit_choices_to={'request': self.request})

With this level of abstraction you can just easily list, modify and add UUID’s to an existing request, or create a different “storage”

l = UUIDList()
l.add(your_uuids)
l.id # will print some id
UUIDItem.objects.filter(request=l.request).all()

Eh voila. Handles your list of UUID’s.

👤Fohlen

Leave a comment