我应该将哪个django表单字段类型用于值数组?

时间:2016-11-29 19:55:37

标签: python django

我在SPA的POST数据中收到最多N uuid4值的数组。我当时应该进入一个删除指定对象实例的视图:

<QueryDict: {'uuids[]' : [
    'a1a241bd-147f-4672-86d7-1a6225b8080e'
    '791db3f0-5134-4927-b328-347c7261d7f6'
    'b8087a1b-710e-47b4-af5a-bae4d5e30532'
    '6d1a96b2-1b99-4707-a8e3-376a0d596d95'
    ...
]}>

据我所知,MultiValueField处理此数据的目的可能并非如此,因为我不想&#34;压缩&#34;它。什么是django处理这样的表单数据的方式?我是否应该手动尝试自己处理request.POST并通过表单运行每个uuid来验证它?或覆盖form.clean()

2 个答案:

答案 0 :(得分:0)

在这种情况下,你可能最适合编写一个可以包含在其他地方的小型模型:

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

你可以很容易地与另一个模型相关:

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})

通过这种抽象级别,您可以轻松地列出,修改和添加UUID到现有请求,或创建不同的“存储”

l = UUIDList()
l.add(your_uuids)
l.id # will print some id
UUIDItem.objects.filter(request=l.request).all()
瞧瞧瞧。处理您的UUID列表。

答案 1 :(得分:0)

我决定使用自定义字段并覆盖post()。如果有更好的方式,我们会感谢评论/编辑。

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