Skip to content

Commit

Permalink
Merge pull request #2239 from jpadilla/allow-blank-choicefield
Browse files Browse the repository at this point in the history
Add allow_blank for ChoiceField #2184
  • Loading branch information
tomchristie committed Dec 9, 2014
2 parents cae19f8 + afe7ed9 commit 54a18a4
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 10 deletions.
5 changes: 5 additions & 0 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -958,9 +958,14 @@ def __init__(self, choices, **kwargs):
(six.text_type(key), key) for key in self.choices.keys()
])

self.allow_blank = kwargs.pop('allow_blank', False)

super(ChoiceField, self).__init__(**kwargs)

def to_internal_value(self, data):
if data == '' and self.allow_blank:
return ''

try:
return self.choice_strings_to_values[six.text_type(data)]
except KeyError:
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ def get_fields(self):
# `ModelField`, which is used when no other typed field
# matched to the model field.
kwargs.pop('model_field', None)
if not issubclass(field_cls, CharField):
if not issubclass(field_cls, CharField) and not issubclass(field_cls, ChoiceField):
# `allow_blank` is only valid for textual fields.
kwargs.pop('allow_blank', None)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{% endif %}
<div class="col-sm-10">
<select class="form-control" name="{{ field.name }}">
{% if field.allow_null %}
{% if field.allow_null or field.allow_blank %}
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
{% endif %}
{% for key, text in field.choices.items %}
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/templates/rest_framework/inline/select.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<label class="sr-only">{{ field.label }}</label>
{% endif %}
<select class="form-control" name="{{ field.name }}">
{% if field.allow_null %}
{% if field.allow_null or field.allow_blank %}
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
{% endif %}
{% for key, text in field.choices.items %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label>
{% endif %}
<select class="form-control" name="{{ field.name }}">
{% if field.allow_null %}
{% if field.allow_null or field.allow_blank %}
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
{% endif %}
{% for key, text in field.choices.items %}
Expand Down
12 changes: 6 additions & 6 deletions rest_framework/utils/field_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,18 @@ def get_field_kwargs(field_name, model_field):
if model_field.has_default() or model_field.blank or model_field.null:
kwargs['required'] = False

if model_field.flatchoices:
# If this model field contains choices, then return early.
# Further keyword arguments are not valid.
kwargs['choices'] = model_field.flatchoices
return kwargs

if model_field.null and not isinstance(model_field, models.NullBooleanField):
kwargs['allow_null'] = True

if model_field.blank:
kwargs['allow_blank'] = True

if model_field.flatchoices:
# If this model field contains choices, then return early.
# Further keyword arguments are not valid.
kwargs['choices'] = model_field.flatchoices
return kwargs

# Ensure that max_length is passed explicitly as a keyword arg,
# rather than as a validator.
max_length = getattr(model_field, 'max_length', None)
Expand Down
15 changes: 15 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,21 @@ class TestChoiceField(FieldValues):
]
)

def test_allow_blank(self):
"""
If `allow_blank=True` then '' is a valid input.
"""
field = serializers.ChoiceField(
allow_blank=True,
choices=[
('poor', 'Poor quality'),
('medium', 'Medium quality'),
('good', 'Good quality'),
]
)
output = field.run_validation('')
assert output is ''


class TestChoiceFieldWithType(FieldValues):
"""
Expand Down

0 comments on commit 54a18a4

Please sign in to comment.