45 lines
1.5 KiB
Python
45 lines
1.5 KiB
Python
"""passbook lib fields"""
|
|
from itertools import chain
|
|
|
|
from django import forms
|
|
from django.contrib.postgres.utils import prefix_validation_error
|
|
|
|
from passbook.lib.widgets import DynamicArrayWidget
|
|
|
|
|
|
class DynamicArrayField(forms.Field):
|
|
"""Show array field as a dynamic amount of textboxes"""
|
|
|
|
default_error_messages = {"item_invalid": "Item %(nth)s in the array did not validate: "}
|
|
|
|
def __init__(self, base_field, **kwargs):
|
|
self.base_field = base_field
|
|
self.max_length = kwargs.pop("max_length", None)
|
|
kwargs.setdefault("widget", DynamicArrayWidget)
|
|
super().__init__(**kwargs)
|
|
|
|
def clean(self, value):
|
|
cleaned_data = []
|
|
errors = []
|
|
value = [x for x in value if x]
|
|
for index, item in enumerate(value):
|
|
try:
|
|
cleaned_data.append(self.base_field.clean(item))
|
|
except forms.ValidationError as error:
|
|
errors.append(
|
|
prefix_validation_error(
|
|
error, self.error_messages["item_invalid"],
|
|
code="item_invalid", params={"nth": index}
|
|
)
|
|
)
|
|
if errors:
|
|
raise forms.ValidationError(list(chain.from_iterable(errors)))
|
|
if not cleaned_data and self.required:
|
|
raise forms.ValidationError(self.error_messages["required"])
|
|
return cleaned_data
|
|
|
|
def has_changed(self, initial, data):
|
|
if not data and not initial:
|
|
return False
|
|
return super().has_changed(initial, data)
|