mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-16 11:12:21 +03:00
Allow ChoiceField.choices
to be set dynamically (#5426)
## Description The `choices` field for the `ChoiceField` class should be able to be edited after `ChoiceField.__init__` is called. ``` field = ChoiceField(choices=[1,2]) field.choices = [1] # Should no longer allow `2` as a choice ``` Currently, you must update `choices`, `grouped_choices`, and `choice_strings_to_values` to achieve this. This P/R keeps `grouped_choices` and `choice_strings_to_values` in sync whenever the `choices` are edited.
This commit is contained in:
parent
7b1582e00e
commit
c0a48622e1
|
@ -1337,18 +1337,10 @@ class ChoiceField(Field):
|
||||||
html_cutoff_text = _('More than {count} items...')
|
html_cutoff_text = _('More than {count} items...')
|
||||||
|
|
||||||
def __init__(self, choices, **kwargs):
|
def __init__(self, choices, **kwargs):
|
||||||
self.grouped_choices = to_choices_dict(choices)
|
self.choices = choices
|
||||||
self.choices = flatten_choices_dict(self.grouped_choices)
|
|
||||||
self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
|
self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
|
||||||
self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
|
self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
|
||||||
|
|
||||||
# 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.allow_blank = kwargs.pop('allow_blank', False)
|
self.allow_blank = kwargs.pop('allow_blank', False)
|
||||||
|
|
||||||
super(ChoiceField, self).__init__(**kwargs)
|
super(ChoiceField, self).__init__(**kwargs)
|
||||||
|
@ -1377,6 +1369,22 @@ class ChoiceField(Field):
|
||||||
cutoff_text=self.html_cutoff_text
|
cutoff_text=self.html_cutoff_text
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _get_choices(self):
|
||||||
|
return self._choices
|
||||||
|
|
||||||
|
def _set_choices(self, choices):
|
||||||
|
self.grouped_choices = to_choices_dict(choices)
|
||||||
|
self._choices = flatten_choices_dict(self.grouped_choices)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
choices = property(_get_choices, _set_choices)
|
||||||
|
|
||||||
|
|
||||||
class MultipleChoiceField(ChoiceField):
|
class MultipleChoiceField(ChoiceField):
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
|
|
|
@ -1425,6 +1425,19 @@ class TestChoiceField(FieldValues):
|
||||||
|
|
||||||
assert items[9].value == 'boolean'
|
assert items[9].value == 'boolean'
|
||||||
|
|
||||||
|
def test_edit_choices(self):
|
||||||
|
field = serializers.ChoiceField(
|
||||||
|
allow_null=True,
|
||||||
|
choices=[
|
||||||
|
1, 2,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
field.choices = [1]
|
||||||
|
assert field.run_validation(1) is 1
|
||||||
|
with pytest.raises(serializers.ValidationError) as exc_info:
|
||||||
|
field.run_validation(2)
|
||||||
|
assert exc_info.value.detail == ['"2" is not a valid choice.']
|
||||||
|
|
||||||
|
|
||||||
class TestChoiceFieldWithType(FieldValues):
|
class TestChoiceFieldWithType(FieldValues):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user