From 9bcd8d60cd12885d73c3560e4fb7f28347043413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20KALA?= Date: Sun, 20 Dec 2015 13:31:09 +0200 Subject: [PATCH] use_value feature added to ChoiceField --- docs/api-guide/fields.md | 1 + rest_framework/fields.py | 17 +++++++++++++++-- tests/test_fields.py | 25 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 4118f6df9..41556f62b 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -366,6 +366,7 @@ Used by `ModelSerializer` to automatically generate fields if the corresponding - `allow_blank` - If set to `True` then the empty string should be considered a valid value. If set to `False` then the empty string is considered invalid and will raise a validation error. Defaults to `False`. - `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to `None`. - `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"` +- `use_value` - If set to `True` then input and output values changed with choice field values. Both the `allow_blank` and `allow_null` are valid options on `ChoiceField`, although it is highly recommended that you only use one and not both. `allow_blank` should be preferred for textual choices, and `allow_null` should be preferred for numeric or other non-textual choices. diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 7bac2a21f..639fe08e0 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1245,12 +1245,23 @@ class ChoiceField(Field): self.choices = flatten_choices_dict(self.grouped_choices) self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff) self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text) + self.use_value = kwargs.pop("use_value", False) # Map the string representation of choices to the underlying value. # Allows us to deal with eg. integer choices while supporting either # integer or string input, but still get the correct datatype out. - self.choice_strings_to_values = { - six.text_type(key): key for key in self.choices.keys() + + if self.use_value: + self.choice_strings_to_values = { + six.text_type(value): key for key, value in self.choices.items() + } + else: + self.choice_strings_to_values = { + six.text_type(key): key for key in self.choices.keys() + } + + self.choice_values_to_strings = { + six.text_type(key): value for key, value in self.choices.items() } self.allow_blank = kwargs.pop('allow_blank', False) @@ -1269,6 +1280,8 @@ class ChoiceField(Field): def to_representation(self, value): if value in ('', None): return value + if self.use_value: + return self.choice_values_to_strings.get(six.text_type(value), value) return self.choice_strings_to_values.get(six.text_type(value), value) def iter_options(self): diff --git a/tests/test_fields.py b/tests/test_fields.py index 029a5bddc..783e0a97c 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -1212,6 +1212,31 @@ class TestChoiceFieldWithType(FieldValues): ) +class TestChoiceFieldWithUseDone(FieldValues): + """ + Valid and invalid values for a `Choice` field that uses an integer type, + instead of a char type. + """ + valid_inputs = { + 'seller': 1, + 'client': 2, + } + invalid_inputs = { + "2": ['"2" is not a valid choice.'] + } + outputs = { + '1': 'seller', + 2: 'client' + } + field = serializers.ChoiceField( + choices=[ + (1, 'seller'), + (2, 'client') + ], + use_value=True + ) + + class TestChoiceFieldWithListChoices(FieldValues): """ Valid and invalid values for a `Choice` field that uses a flat list for the