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