mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-09-21 11:29:01 +03:00
Merge pull request #1214 from diox/choicefield-typed
Improve handling of 'empty' values for ChoiceField
This commit is contained in:
commit
97430c0d9c
|
@ -497,6 +497,7 @@ class ChoiceField(WritableField):
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, choices=(), *args, **kwargs):
|
def __init__(self, choices=(), *args, **kwargs):
|
||||||
|
self.empty = kwargs.pop('empty', '')
|
||||||
super(ChoiceField, self).__init__(*args, **kwargs)
|
super(ChoiceField, self).__init__(*args, **kwargs)
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
if not self.required:
|
if not self.required:
|
||||||
|
@ -537,9 +538,10 @@ class ChoiceField(WritableField):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def from_native(self, value):
|
def from_native(self, value):
|
||||||
if value in validators.EMPTY_VALUES:
|
value = super(ChoiceField, self).from_native(value)
|
||||||
return None
|
if value == self.empty or value in validators.EMPTY_VALUES:
|
||||||
return super(ChoiceField, self).from_native(value)
|
return self.empty
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class EmailField(CharField):
|
class EmailField(CharField):
|
||||||
|
|
|
@ -794,6 +794,8 @@ class ModelSerializer(Serializer):
|
||||||
# TODO: TypedChoiceField?
|
# TODO: TypedChoiceField?
|
||||||
if model_field.flatchoices: # This ModelField contains choices
|
if model_field.flatchoices: # This ModelField contains choices
|
||||||
kwargs['choices'] = model_field.flatchoices
|
kwargs['choices'] = model_field.flatchoices
|
||||||
|
if model_field.null:
|
||||||
|
kwargs['empty'] = None
|
||||||
return ChoiceField(**kwargs)
|
return ChoiceField(**kwargs)
|
||||||
|
|
||||||
# put this below the ChoiceField because min_value isn't a valid initializer
|
# put this below the ChoiceField because min_value isn't a valid initializer
|
||||||
|
|
|
@ -42,6 +42,31 @@ class TimeFieldModelSerializer(serializers.ModelSerializer):
|
||||||
model = TimeFieldModel
|
model = TimeFieldModel
|
||||||
|
|
||||||
|
|
||||||
|
SAMPLE_CHOICES = [
|
||||||
|
('red', 'Red'),
|
||||||
|
('green', 'Green'),
|
||||||
|
('blue', 'Blue'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiceFieldModel(models.Model):
|
||||||
|
choice = models.CharField(choices=SAMPLE_CHOICES, blank=True, max_length=255)
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiceFieldModelSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ChoiceFieldModel
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiceFieldModelWithNull(models.Model):
|
||||||
|
choice = models.CharField(choices=SAMPLE_CHOICES, blank=True, null=True, max_length=255)
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiceFieldModelWithNullSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ChoiceFieldModelWithNull
|
||||||
|
|
||||||
|
|
||||||
class BasicFieldTests(TestCase):
|
class BasicFieldTests(TestCase):
|
||||||
def test_auto_now_fields_read_only(self):
|
def test_auto_now_fields_read_only(self):
|
||||||
"""
|
"""
|
||||||
|
@ -667,34 +692,53 @@ class ChoiceFieldTests(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for the ChoiceField options generator
|
Tests for the ChoiceField options generator
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SAMPLE_CHOICES = [
|
|
||||||
('red', 'Red'),
|
|
||||||
('green', 'Green'),
|
|
||||||
('blue', 'Blue'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_choices_required(self):
|
def test_choices_required(self):
|
||||||
"""
|
"""
|
||||||
Make sure proper choices are rendered if field is required
|
Make sure proper choices are rendered if field is required
|
||||||
"""
|
"""
|
||||||
f = serializers.ChoiceField(required=True, choices=self.SAMPLE_CHOICES)
|
f = serializers.ChoiceField(required=True, choices=SAMPLE_CHOICES)
|
||||||
self.assertEqual(f.choices, self.SAMPLE_CHOICES)
|
self.assertEqual(f.choices, SAMPLE_CHOICES)
|
||||||
|
|
||||||
def test_choices_not_required(self):
|
def test_choices_not_required(self):
|
||||||
"""
|
"""
|
||||||
Make sure proper choices (plus blank) are rendered if the field isn't required
|
Make sure proper choices (plus blank) are rendered if the field isn't required
|
||||||
"""
|
"""
|
||||||
f = serializers.ChoiceField(required=False, choices=self.SAMPLE_CHOICES)
|
f = serializers.ChoiceField(required=False, choices=SAMPLE_CHOICES)
|
||||||
self.assertEqual(f.choices, models.fields.BLANK_CHOICE_DASH + self.SAMPLE_CHOICES)
|
self.assertEqual(f.choices, models.fields.BLANK_CHOICE_DASH + SAMPLE_CHOICES)
|
||||||
|
|
||||||
|
def test_invalid_choice_model(self):
|
||||||
|
s = ChoiceFieldModelSerializer(data={'choice' : 'wrong_value'})
|
||||||
|
self.assertFalse(s.is_valid())
|
||||||
|
self.assertEqual(s.errors, {'choice': ['Select a valid choice. wrong_value is not one of the available choices.']})
|
||||||
|
self.assertEqual(s.data['choice'], '')
|
||||||
|
|
||||||
|
def test_empty_choice_model(self):
|
||||||
|
"""
|
||||||
|
Test that the 'empty' value is correctly passed and used depending on the 'null' property on the model field.
|
||||||
|
"""
|
||||||
|
s = ChoiceFieldModelSerializer(data={'choice' : ''})
|
||||||
|
self.assertTrue(s.is_valid())
|
||||||
|
self.assertEqual(s.data['choice'], '')
|
||||||
|
|
||||||
|
s = ChoiceFieldModelWithNullSerializer(data={'choice' : ''})
|
||||||
|
self.assertTrue(s.is_valid())
|
||||||
|
self.assertEqual(s.data['choice'], None)
|
||||||
|
|
||||||
def test_from_native_empty(self):
|
def test_from_native_empty(self):
|
||||||
"""
|
"""
|
||||||
Make sure from_native() returns None on empty param.
|
Make sure from_native() returns an empty string on empty param by default.
|
||||||
"""
|
"""
|
||||||
f = serializers.ChoiceField(choices=self.SAMPLE_CHOICES)
|
f = serializers.ChoiceField(choices=SAMPLE_CHOICES)
|
||||||
result = f.from_native('')
|
self.assertEqual(f.from_native(''), '')
|
||||||
self.assertEqual(result, None)
|
self.assertEqual(f.from_native(None), '')
|
||||||
|
|
||||||
|
def test_from_native_empty_override(self):
|
||||||
|
"""
|
||||||
|
Make sure you can override from_native() behavior regarding empty values.
|
||||||
|
"""
|
||||||
|
f = serializers.ChoiceField(choices=SAMPLE_CHOICES, empty=None)
|
||||||
|
self.assertEqual(f.from_native(''), None)
|
||||||
|
self.assertEqual(f.from_native(None), None)
|
||||||
|
|
||||||
|
|
||||||
class EmailFieldTests(TestCase):
|
class EmailFieldTests(TestCase):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user