Skip to content

Commit 23031be

Browse files
authored
Merge pull request #191 from novafloss/skip-presets-on-empty-fields
Skip form validation rules if a field is empty
2 parents 90854f5 + 82080b1 commit 23031be

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

demo/tests/test_forms.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
from freezegun import freeze_time
1313

1414
from formidable.constants import REQUIRED, EDITABLE, READONLY, HIDDEN
15-
from formidable.models import Formidable
15+
from formidable.models import Formidable, PresetArg
1616
from formidable.forms import FormidableForm, widgets, fields
17+
from formidable.forms.validations.presets import ConfirmationPresets
1718

1819

1920
class TestDynamicForm(TestCase):
@@ -776,3 +777,80 @@ def test_from_json_raised_error(self):
776777
self.assertEqual(len(context.exception.messages), 3)
777778
for message in context.exception.messages:
778779
self.assertEqual(message, 'This field is required.')
780+
781+
782+
class TestInnerPresets(TestCase):
783+
784+
def test_confirmation_not_required_field(self):
785+
class TestPresets(FormidableForm):
786+
number = fields.IntegerField(accesses={
787+
'jedi': EDITABLE,
788+
})
789+
text = fields.CharField(accesses={
790+
'jedi': EDITABLE,
791+
})
792+
793+
class Meta:
794+
presets = [
795+
ConfirmationPresets(
796+
[PresetArg(slug='left', field_id='number'),
797+
PresetArg(slug='right', value='42')],
798+
),
799+
ConfirmationPresets(
800+
[PresetArg(slug='left', field_id='text'),
801+
PresetArg(slug='right', value='toto')],
802+
),
803+
]
804+
805+
formidable = TestPresets.to_formidable(label='presets')
806+
form_class = formidable.get_django_form_class(role='jedi')
807+
form = form_class(data={'number': '', 'text': ''})
808+
self.assertEqual(len(form.rules), 2)
809+
self.assertTrue(form.is_valid(), form.errors)
810+
811+
def test_confirmation_not_required_fields(self):
812+
class TestPresets(FormidableForm):
813+
left = fields.IntegerField(accesses={
814+
'jedi': REQUIRED,
815+
})
816+
right = fields.IntegerField(accesses={
817+
'jedi': REQUIRED,
818+
})
819+
820+
class Meta:
821+
presets = [
822+
ConfirmationPresets(
823+
[PresetArg(slug='left', field_id='left'),
824+
PresetArg(slug='right', field_id='right')],
825+
),
826+
]
827+
828+
formidable = TestPresets.to_formidable(label='presets')
829+
form_class = formidable.get_django_form_class(role='padawan')
830+
form = form_class(data={'left': '', 'right': ''})
831+
self.assertTrue(form.is_valid(), form.errors)
832+
833+
def test_confirmation_required_fields(self):
834+
class TestPresets(FormidableForm):
835+
left = fields.IntegerField(accesses={
836+
'jedi': REQUIRED,
837+
})
838+
right = fields.IntegerField(accesses={
839+
'jedi': REQUIRED,
840+
})
841+
842+
class Meta:
843+
presets = [
844+
ConfirmationPresets(
845+
[PresetArg(slug='left', field_id='left'),
846+
PresetArg(slug='right', field_id='right')],
847+
),
848+
]
849+
850+
formidable = TestPresets.to_formidable(label='presets')
851+
form_class = formidable.get_django_form_class(role='jedi')
852+
form = form_class(data={'left': '', 'right': ''})
853+
self.assertFalse(form.is_valid(), form.errors)
854+
self.assertEqual(len(form.errors), 2)
855+
self.assertIn('left', form.errors)
856+
self.assertIn('right', form.errors)

formidable/forms/validations/presets.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,25 @@ def __init__(self, arguments, message=None):
147147
self.arguments = arguments
148148
self.message = message or self.default_message
149149

150+
def has_empty_fields(self, cleaned_data):
151+
def is_empty_value(data):
152+
return (data is None or
153+
(isinstance(data, six.string_types) and not data))
154+
155+
used_fields = {a.field_id for a in self.arguments if a.field_id}
156+
# we do not filter out required fields because they can't be empty
157+
return any(
158+
is_empty_value(cleaned_data.get(name, None))
159+
for name in used_fields
160+
)
161+
150162
def __call__(self, cleaned_data):
163+
if self.has_empty_fields(cleaned_data):
164+
# We skip rules using empty fields
165+
# If the fields were required then it is already reported in
166+
# form.errors. If the fields were not required, then it is not
167+
# useful to report an error
168+
return True
151169
kwargs = self.collect_kwargs(cleaned_data)
152170
if not self.run(**kwargs):
153171
raise ValidationError(self.get_message(kwargs))

0 commit comments

Comments
 (0)