diff options
| author | Tom Christie | 2014-12-09 14:08:45 +0000 |
|---|---|---|
| committer | Tom Christie | 2014-12-09 14:08:45 +0000 |
| commit | 54a18a4ddb69bb43c13e45f151b075564dd771b2 (patch) | |
| tree | c392eb5c1afba4dee29d67c2e67411b957371bdf | |
| parent | cae19f8924c598cea93a546138757ff48eed9f75 (diff) | |
| parent | afe7ed9333e37384f8ddc57e891da9632c8714c3 (diff) | |
| download | django-rest-framework-54a18a4ddb69bb43c13e45f151b075564dd771b2.tar.bz2 | |
Merge pull request #2239 from jpadilla/allow-blank-choicefield
Add allow_blank for ChoiceField #2184
| -rw-r--r-- | rest_framework/fields.py | 5 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 2 | ||||
| -rw-r--r-- | rest_framework/templates/rest_framework/horizontal/select.html | 2 | ||||
| -rw-r--r-- | rest_framework/templates/rest_framework/inline/select.html | 2 | ||||
| -rw-r--r-- | rest_framework/templates/rest_framework/vertical/select.html | 2 | ||||
| -rw-r--r-- | rest_framework/utils/field_mapping.py | 12 | ||||
| -rw-r--r-- | tests/test_fields.py | 15 |
7 files changed, 30 insertions, 10 deletions
diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 0c6c2d39..99498da7 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -958,9 +958,14 @@ class ChoiceField(Field): (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: diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index fb6c826b..b0c0efa7 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -942,7 +942,7 @@ class ModelSerializer(Serializer): # `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) diff --git a/rest_framework/templates/rest_framework/horizontal/select.html b/rest_framework/templates/rest_framework/horizontal/select.html index 380b38e9..8a7fca37 100644 --- a/rest_framework/templates/rest_framework/horizontal/select.html +++ b/rest_framework/templates/rest_framework/horizontal/select.html @@ -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 %} diff --git a/rest_framework/templates/rest_framework/inline/select.html b/rest_framework/templates/rest_framework/inline/select.html index 53af2772..6b30e4d6 100644 --- a/rest_framework/templates/rest_framework/inline/select.html +++ b/rest_framework/templates/rest_framework/inline/select.html @@ -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 %} diff --git a/rest_framework/templates/rest_framework/vertical/select.html b/rest_framework/templates/rest_framework/vertical/select.html index de72e1dd..1d1109f6 100644 --- a/rest_framework/templates/rest_framework/vertical/select.html +++ b/rest_framework/templates/rest_framework/vertical/select.html @@ -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 %} diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 9c187176..86ceff31 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -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) diff --git a/tests/test_fields.py b/tests/test_fields.py index 13525632..3f4e65f2 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -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): """ |
