mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 01:26:53 +03:00
Fix mapping for choice values (#8968)
* fix mapping for choice values * fix tests for ChoiceField IntegerChoices * fix imports * fix imports in tests * Check for multiple choice enums * fix formatting * add tests for text choices class
This commit is contained in:
parent
d14eb7555d
commit
e08e606c82
|
@ -16,6 +16,7 @@ from django.core.validators import (
|
||||||
MinValueValidator, ProhibitNullCharactersValidator, RegexValidator,
|
MinValueValidator, ProhibitNullCharactersValidator, RegexValidator,
|
||||||
URLValidator, ip_address_validators
|
URLValidator, ip_address_validators
|
||||||
)
|
)
|
||||||
|
from django.db.models import IntegerChoices, TextChoices
|
||||||
from django.forms import FilePathField as DjangoFilePathField
|
from django.forms import FilePathField as DjangoFilePathField
|
||||||
from django.forms import ImageField as DjangoImageField
|
from django.forms import ImageField as DjangoImageField
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -1397,6 +1398,10 @@ class ChoiceField(Field):
|
||||||
if data == '' and self.allow_blank:
|
if data == '' and self.allow_blank:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
if isinstance(data, (IntegerChoices, TextChoices)) and str(data) != \
|
||||||
|
str(data.value):
|
||||||
|
data = data.value
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.choice_strings_to_values[str(data)]
|
return self.choice_strings_to_values[str(data)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1405,6 +1410,11 @@ class ChoiceField(Field):
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
if value in ('', None):
|
if value in ('', None):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, (IntegerChoices, TextChoices)) and str(value) != \
|
||||||
|
str(value.value):
|
||||||
|
value = value.value
|
||||||
|
|
||||||
return self.choice_strings_to_values.get(str(value), value)
|
return self.choice_strings_to_values.get(str(value), value)
|
||||||
|
|
||||||
def iter_options(self):
|
def iter_options(self):
|
||||||
|
@ -1428,7 +1438,8 @@ class ChoiceField(Field):
|
||||||
# Allows us to deal with eg. integer choices while supporting either
|
# Allows us to deal with eg. integer choices while supporting either
|
||||||
# integer or string input, but still get the correct datatype out.
|
# integer or string input, but still get the correct datatype out.
|
||||||
self.choice_strings_to_values = {
|
self.choice_strings_to_values = {
|
||||||
str(key): key for key in self.choices
|
str(key.value) if isinstance(key, (IntegerChoices, TextChoices))
|
||||||
|
and str(key) != str(key.value) else str(key): key for key in self.choices
|
||||||
}
|
}
|
||||||
|
|
||||||
choices = property(_get_choices, _set_choices)
|
choices = property(_get_choices, _set_choices)
|
||||||
|
|
|
@ -5,11 +5,13 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
from decimal import ROUND_DOWN, ROUND_UP, Decimal
|
from decimal import ROUND_DOWN, ROUND_UP, Decimal
|
||||||
|
from enum import auto
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytz
|
import pytz
|
||||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||||
|
from django.db.models import IntegerChoices, TextChoices
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.utils.timezone import activate, deactivate, override
|
from django.utils.timezone import activate, deactivate, override
|
||||||
|
@ -1824,6 +1826,54 @@ class TestChoiceField(FieldValues):
|
||||||
field.run_validation(2)
|
field.run_validation(2)
|
||||||
assert exc_info.value.detail == ['"2" is not a valid choice.']
|
assert exc_info.value.detail == ['"2" is not a valid choice.']
|
||||||
|
|
||||||
|
def test_integer_choices(self):
|
||||||
|
class ChoiceCase(IntegerChoices):
|
||||||
|
first = auto()
|
||||||
|
second = auto()
|
||||||
|
# Enum validate
|
||||||
|
choices = [
|
||||||
|
(ChoiceCase.first, "1"),
|
||||||
|
(ChoiceCase.second, "2")
|
||||||
|
]
|
||||||
|
|
||||||
|
field = serializers.ChoiceField(choices=choices)
|
||||||
|
assert field.run_validation(1) == 1
|
||||||
|
assert field.run_validation(ChoiceCase.first) == 1
|
||||||
|
assert field.run_validation("1") == 1
|
||||||
|
|
||||||
|
choices = [
|
||||||
|
(ChoiceCase.first.value, "1"),
|
||||||
|
(ChoiceCase.second.value, "2")
|
||||||
|
]
|
||||||
|
|
||||||
|
field = serializers.ChoiceField(choices=choices)
|
||||||
|
assert field.run_validation(1) == 1
|
||||||
|
assert field.run_validation(ChoiceCase.first) == 1
|
||||||
|
assert field.run_validation("1") == 1
|
||||||
|
|
||||||
|
def test_text_choices(self):
|
||||||
|
class ChoiceCase(TextChoices):
|
||||||
|
first = auto()
|
||||||
|
second = auto()
|
||||||
|
# Enum validate
|
||||||
|
choices = [
|
||||||
|
(ChoiceCase.first, "first"),
|
||||||
|
(ChoiceCase.second, "second")
|
||||||
|
]
|
||||||
|
|
||||||
|
field = serializers.ChoiceField(choices=choices)
|
||||||
|
assert field.run_validation(ChoiceCase.first) == "first"
|
||||||
|
assert field.run_validation("first") == "first"
|
||||||
|
|
||||||
|
choices = [
|
||||||
|
(ChoiceCase.first.value, "first"),
|
||||||
|
(ChoiceCase.second.value, "second")
|
||||||
|
]
|
||||||
|
|
||||||
|
field = serializers.ChoiceField(choices=choices)
|
||||||
|
assert field.run_validation(ChoiceCase.first) == "first"
|
||||||
|
assert field.run_validation("first") == "first"
|
||||||
|
|
||||||
|
|
||||||
class TestChoiceFieldWithType(FieldValues):
|
class TestChoiceFieldWithType(FieldValues):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user