Skip to content

Commit e14391e

Browse files
committed
Fix for ModelSerializer ChoiceField with nonstandard args. Closes #3126.
1 parent 713333d commit e14391e

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

rest_framework/serializers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,19 @@ def build_standard_field(self, field_name, model_field):
10331033
# Fields with choices get coerced into `ChoiceField`
10341034
# instead of using their regular typed field.
10351035
field_class = self.serializer_choice_field
1036+
# Some model fields may introduce kwargs that would not be valid
1037+
# for the choice field. We need to strip these out.
1038+
# Eg. models.DecimalField(max_digits=3, decimal_places=1, choices=DECIMAL_CHOICES)
1039+
valid_kwargs = set((
1040+
'read_only', 'write_only',
1041+
'required', 'default', 'initial', 'source',
1042+
'label', 'help_text', 'style',
1043+
'error_messages', 'validators', 'allow_null', 'allow_blank',
1044+
'choices'
1045+
))
1046+
for key in list(field_kwargs.keys()):
1047+
if key not in valid_kwargs:
1048+
field_kwargs.pop(key)
10361049

10371050
if not issubclass(field_class, ModelField):
10381051
# `model_field` is only valid for the fallback case of

tests/test_model_serializer.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"""
88
from __future__ import unicode_literals
99

10+
import decimal
11+
1012
import django
1113
import pytest
1214
from django.core.exceptions import ImproperlyConfigured
@@ -70,6 +72,7 @@ def method(self):
7072

7173

7274
COLOR_CHOICES = (('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))
75+
DECIMAL_CHOICES = (('low', decimal.Decimal('0.1')), ('medium', decimal.Decimal('0.5')), ('high', decimal.Decimal('0.9')))
7376

7477

7578
class FieldOptionsModel(models.Model):
@@ -82,6 +85,10 @@ class FieldOptionsModel(models.Model):
8285
choices_field = models.CharField(max_length=100, choices=COLOR_CHOICES)
8386

8487

88+
class MappingForChoicesWithNonStandardArgs(models.Model):
89+
choices_field_with_nonstandard_args = models.DecimalField(max_digits=3, decimal_places=1, choices=DECIMAL_CHOICES)
90+
91+
8592
class TestModelSerializer(TestCase):
8693
def test_create_method(self):
8794
class TestSerializer(serializers.ModelSerializer):
@@ -307,6 +314,13 @@ class Meta:
307314

308315
ChildSerializer().fields
309316

317+
def test_choices_with_nonstandard_args(self):
318+
class ExampleSerializer(serializers.ModelSerializer):
319+
class Meta:
320+
model = MappingForChoicesWithNonStandardArgs
321+
322+
ExampleSerializer()
323+
310324

311325
@pytest.mark.skipif(django.VERSION < (1, 8),
312326
reason='DurationField is only available for django1.8+')

0 commit comments

Comments
 (0)