mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-03 13:14:30 +03:00
fix unique=True validation for ChoiceField
This commit is contained in:
parent
63a4021472
commit
56fe0e4b3f
|
@ -123,18 +123,70 @@ def get_field_kwargs(field_name, model_field):
|
||||||
kwargs['allow_folders'] = model_field.allow_folders
|
kwargs['allow_folders'] = model_field.allow_folders
|
||||||
|
|
||||||
if model_field.choices:
|
if model_field.choices:
|
||||||
# If this model field contains choices, then return early.
|
|
||||||
# Further keyword arguments are not valid.
|
|
||||||
kwargs['choices'] = model_field.choices
|
kwargs['choices'] = model_field.choices
|
||||||
return kwargs
|
else:
|
||||||
|
# Ensure that max_value is passed explicitly as a keyword arg,
|
||||||
|
# rather than as a validator.
|
||||||
|
max_value = next((
|
||||||
|
validator.limit_value for validator in validator_kwarg
|
||||||
|
if isinstance(validator, validators.MaxValueValidator)
|
||||||
|
), None)
|
||||||
|
if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
|
||||||
|
kwargs['max_value'] = max_value
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if not isinstance(validator, validators.MaxValueValidator)
|
||||||
|
]
|
||||||
|
|
||||||
# Our decimal validation is handled in the field code, not validator code.
|
# Ensure that max_value is passed explicitly as a keyword arg,
|
||||||
# (In Django 1.9+ this differs from previous style)
|
# rather than as a validator.
|
||||||
if isinstance(model_field, models.DecimalField) and DecimalValidator:
|
min_value = next((
|
||||||
validator_kwarg = [
|
validator.limit_value for validator in validator_kwarg
|
||||||
validator for validator in validator_kwarg
|
if isinstance(validator, validators.MinValueValidator)
|
||||||
if not isinstance(validator, DecimalValidator)
|
), None)
|
||||||
]
|
if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
|
||||||
|
kwargs['min_value'] = min_value
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if not isinstance(validator, validators.MinValueValidator)
|
||||||
|
]
|
||||||
|
|
||||||
|
# URLField does not need to include the URLValidator argument,
|
||||||
|
# as it is explicitly added in.
|
||||||
|
if isinstance(model_field, models.URLField):
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if not isinstance(validator, validators.URLValidator)
|
||||||
|
]
|
||||||
|
|
||||||
|
# EmailField does not need to include the validate_email argument,
|
||||||
|
# as it is explicitly added in.
|
||||||
|
if isinstance(model_field, models.EmailField):
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if validator is not validators.validate_email
|
||||||
|
]
|
||||||
|
|
||||||
|
# SlugField do not need to include the 'validate_slug' argument,
|
||||||
|
if isinstance(model_field, models.SlugField):
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if validator is not validators.validate_slug
|
||||||
|
]
|
||||||
|
|
||||||
|
# IPAddressField do not need to include the 'validate_ipv46_address' argument,
|
||||||
|
if isinstance(model_field, models.GenericIPAddressField):
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if validator is not validators.validate_ipv46_address
|
||||||
|
]
|
||||||
|
# Our decimal validation is handled in the field code, not validator code.
|
||||||
|
# (In Django 1.9+ this differs from previous style)
|
||||||
|
if isinstance(model_field, models.DecimalField) and DecimalValidator:
|
||||||
|
validator_kwarg = [
|
||||||
|
validator for validator in validator_kwarg
|
||||||
|
if not isinstance(validator, DecimalValidator)
|
||||||
|
]
|
||||||
|
|
||||||
# Ensure that max_length is passed explicitly as a keyword arg,
|
# Ensure that max_length is passed explicitly as a keyword arg,
|
||||||
# rather than as a validator.
|
# rather than as a validator.
|
||||||
|
@ -160,62 +212,6 @@ def get_field_kwargs(field_name, model_field):
|
||||||
if not isinstance(validator, validators.MinLengthValidator)
|
if not isinstance(validator, validators.MinLengthValidator)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Ensure that max_value is passed explicitly as a keyword arg,
|
|
||||||
# rather than as a validator.
|
|
||||||
max_value = next((
|
|
||||||
validator.limit_value for validator in validator_kwarg
|
|
||||||
if isinstance(validator, validators.MaxValueValidator)
|
|
||||||
), None)
|
|
||||||
if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
|
|
||||||
kwargs['max_value'] = max_value
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if not isinstance(validator, validators.MaxValueValidator)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Ensure that max_value is passed explicitly as a keyword arg,
|
|
||||||
# rather than as a validator.
|
|
||||||
min_value = next((
|
|
||||||
validator.limit_value for validator in validator_kwarg
|
|
||||||
if isinstance(validator, validators.MinValueValidator)
|
|
||||||
), None)
|
|
||||||
if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
|
|
||||||
kwargs['min_value'] = min_value
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if not isinstance(validator, validators.MinValueValidator)
|
|
||||||
]
|
|
||||||
|
|
||||||
# URLField does not need to include the URLValidator argument,
|
|
||||||
# as it is explicitly added in.
|
|
||||||
if isinstance(model_field, models.URLField):
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if not isinstance(validator, validators.URLValidator)
|
|
||||||
]
|
|
||||||
|
|
||||||
# EmailField does not need to include the validate_email argument,
|
|
||||||
# as it is explicitly added in.
|
|
||||||
if isinstance(model_field, models.EmailField):
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if validator is not validators.validate_email
|
|
||||||
]
|
|
||||||
|
|
||||||
# SlugField do not need to include the 'validate_slug' argument,
|
|
||||||
if isinstance(model_field, models.SlugField):
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if validator is not validators.validate_slug
|
|
||||||
]
|
|
||||||
|
|
||||||
# IPAddressField do not need to include the 'validate_ipv46_address' argument,
|
|
||||||
if isinstance(model_field, models.GenericIPAddressField):
|
|
||||||
validator_kwarg = [
|
|
||||||
validator for validator in validator_kwarg
|
|
||||||
if validator is not validators.validate_ipv46_address
|
|
||||||
]
|
|
||||||
|
|
||||||
if getattr(model_field, 'unique', False):
|
if getattr(model_field, 'unique', False):
|
||||||
unique_error_message = model_field.error_messages.get('unique', None)
|
unique_error_message = model_field.error_messages.get('unique', None)
|
||||||
if unique_error_message:
|
if unique_error_message:
|
||||||
|
|
|
@ -519,3 +519,29 @@ class TestDeclaredFieldInheritance:
|
||||||
assert len(Parent().get_fields()) == 2
|
assert len(Parent().get_fields()) == 2
|
||||||
assert len(Child().get_fields()) == 2
|
assert len(Child().get_fields()) == 2
|
||||||
assert len(Grandchild().get_fields()) == 2
|
assert len(Grandchild().get_fields()) == 2
|
||||||
|
|
||||||
|
|
||||||
|
class Poll(models.Model):
|
||||||
|
CHOICES = (
|
||||||
|
('choice1', 'choice 1'),
|
||||||
|
('choice2', 'choice 1'),
|
||||||
|
)
|
||||||
|
|
||||||
|
name = models.CharField(
|
||||||
|
'name', max_length=254, unique=True, choices=CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class Test5004UniqueChoiceField:
|
||||||
|
def test_unique_choice_field(self):
|
||||||
|
Poll.objects.create(name='choice1')
|
||||||
|
|
||||||
|
class PollSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Poll
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
serializer = PollSerializer(data={'name': 'choice1'})
|
||||||
|
assert not serializer.is_valid()
|
||||||
|
assert serializer.errors == {'name': ['poll with this name already exists.']}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user