Skip to content

Commit

Permalink
Enable customization of SimpleListField
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Chainz committed Jun 1, 2015
1 parent 11a11f2 commit 17efca3
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 13 deletions.
48 changes: 35 additions & 13 deletions django_mysql/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,29 @@

class SimpleListField(forms.CharField):

# These bits can be overridden simply to change the way the field works

default_error_messages = {
'item_n_invalid': _('Item %(nth)s in the list did not validate: '),
'no_double_commas': _('No leading, trailing, or double commas.'),
'items_no_commas': _('No leading, trailing, or double commas.'),
# The 'empty' message is the same as 'no commas' by default, since the
# only reason empty strings could arise with the basic comma-splitting
# logic is with extra commas. This may not be true in custom subclasses
# however.
'items_no_empty': _('No leading, trailing, or double commas.'),
}

def prepare_value_serialize(self, values):
return ",".join(values)

def to_python_deserialize(self, value):
if not value:
return []
else:
return value.split(",")

# Internals

def __init__(self, base_field, max_length=None, min_length=None,
*args, **kwargs):
self.base_field = base_field
Expand All @@ -36,25 +54,29 @@ def __init__(self, base_field, max_length=None, min_length=None,

def prepare_value(self, value):
if isinstance(value, list):
return ",".join(
six.text_type(self.base_field.prepare_value(v))
for v in value
return self.prepare_value_serialize(
(six.text_type(self.base_field.prepare_value(v))
for v in value)
)
return value

def to_python(self, value):
if value and len(value):
items = value.split(",")
else:
items = []
items = self.to_python_deserialize(value)

errors = []
values = []
for i, item in enumerate(items, start=1):
if not len(item):
errors.append(ValidationError(
self.error_messages['no_double_commas'],
code='no_double_commas',
self.error_messages['items_no_empty'],
code='items_no_empty',
))
continue

if ',' in item:
errors.append(ValidationError(
self.error_messages['items_no_commas'],
code='items_no_commas',
))
continue

Expand Down Expand Up @@ -121,7 +143,7 @@ class SimpleSetField(forms.CharField):
default_error_messages = {
'item_invalid': _('Item "%(item)s" in the set did not validate: '),
'item_n_invalid': _('Item %(nth)s in the set did not validate: '),
'no_double_commas': _('No leading, trailing, or double commas.'),
'items_no_commas': _('No leading, trailing, or double commas.'),
'no_duplicates': _("Duplicates are not supported. "
"'%(item)s' appears twice or more.")
}
Expand Down Expand Up @@ -156,8 +178,8 @@ def to_python(self, value):
for i, item in enumerate(items, start=1):
if not len(item):
errors.append(ValidationError(
self.error_messages['no_double_commas'],
code='no_double_commas',
self.error_messages['items_no_commas'],
code='items_no_commas',
))
continue

Expand Down
63 changes: 63 additions & 0 deletions tests/django_mysql_tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,69 @@ def test_required(self):
assert excinfo.value.messages[0] == 'This field is required.'


class CustomListField(SimpleListField):

default_error_messages = dict(
SimpleListField.default_error_messages,
items_no_commas="Commas are not allowed.",
items_no_empty="Empty lines are not allowed."
)

def prepare_value_serialize(self, values):
return "\n".join(values)

def to_python_deserialize(self, value):
if not value:
return []
else:
return value.splitlines()


class CustomListFieldTests(TestCase):
"""
Check that we can subclass SimpleListField and replace how data is
converted back and forth from the form easily
"""
def test_valid(self):
field = CustomListField(forms.CharField())
value = field.clean('a\nb\nc')
assert value == ['a', 'b', 'c']

def test_to_python_no_empties(self):
field = CustomListField(forms.IntegerField())
with pytest.raises(exceptions.ValidationError) as excinfo:
field.clean('\n\n')
assert (
excinfo.value.messages[0] ==
'Empty lines are not allowed.'
)

def test_to_python_no_commas(self):
field = CustomListField(forms.IntegerField())
with pytest.raises(exceptions.ValidationError) as excinfo:
field.clean(',1')
assert (
excinfo.value.messages[0] ==
'Commas are not allowed.'
)

def test_to_python_base_field_does_not_validate(self):
field = CustomListField(forms.IntegerField())
with pytest.raises(exceptions.ValidationError) as excinfo:
field.clean('a\nb\n9')
assert (
excinfo.value.messages[0] ==
'Item 1 in the list did not validate: Enter a whole number.'
)

def test_prepare_value(self):
field = CustomListField(forms.CharField())
value = field.prepare_value(['a', 'b', 'c'])
assert value.split('\n') == ['a', 'b', 'c']

assert field.prepare_value('1\na') == '1\na'


class TestSimpleSetField(TestCase):

def test_valid(self):
Expand Down

0 comments on commit 17efca3

Please sign in to comment.