mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-29 04:54:00 +03:00
9d06e43d05
As all source files import unicode_literals, type('') is always equivalent to six.text_type (str on Python 3 and unicode on Python 2). Removes the need to call type(), is more explicit, and will be easier to catch places to change for when it is time to eventually drop Python 2.
258 lines
8.1 KiB
Python
258 lines
8.1 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import re
|
|
|
|
from django.core.validators import MaxValueValidator, RegexValidator
|
|
from django.db import models
|
|
from django.test import TestCase
|
|
from django.utils import six
|
|
|
|
from rest_framework import generics, serializers, status
|
|
from rest_framework.test import APIRequestFactory
|
|
|
|
factory = APIRequestFactory()
|
|
|
|
|
|
# Regression for #666
|
|
|
|
class ValidationModel(models.Model):
|
|
blank_validated_field = models.CharField(max_length=255)
|
|
|
|
|
|
class ValidationModelSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = ValidationModel
|
|
fields = ('blank_validated_field',)
|
|
read_only_fields = ('blank_validated_field',)
|
|
|
|
|
|
class UpdateValidationModel(generics.RetrieveUpdateDestroyAPIView):
|
|
queryset = ValidationModel.objects.all()
|
|
serializer_class = ValidationModelSerializer
|
|
|
|
|
|
# Regression for #653
|
|
|
|
class ShouldValidateModel(models.Model):
|
|
should_validate_field = models.CharField(max_length=255)
|
|
|
|
|
|
class ShouldValidateModelSerializer(serializers.ModelSerializer):
|
|
renamed = serializers.CharField(source='should_validate_field', required=False)
|
|
|
|
def validate_renamed(self, value):
|
|
if len(value) < 3:
|
|
raise serializers.ValidationError('Minimum 3 characters.')
|
|
return value
|
|
|
|
class Meta:
|
|
model = ShouldValidateModel
|
|
fields = ('renamed',)
|
|
|
|
|
|
class TestNestedValidationError(TestCase):
|
|
def test_nested_validation_error_detail(self):
|
|
"""
|
|
Ensure nested validation error detail is rendered correctly.
|
|
"""
|
|
e = serializers.ValidationError({
|
|
'nested': {
|
|
'field': ['error'],
|
|
}
|
|
})
|
|
|
|
assert serializers.as_serializer_error(e) == {
|
|
'nested': {
|
|
'field': ['error'],
|
|
}
|
|
}
|
|
|
|
|
|
class TestPreSaveValidationExclusionsSerializer(TestCase):
|
|
def test_renamed_fields_are_model_validated(self):
|
|
"""
|
|
Ensure fields with 'source' applied do get still get model validation.
|
|
"""
|
|
# We've set `required=False` on the serializer, but the model
|
|
# does not have `blank=True`, so this serializer should not validate.
|
|
serializer = ShouldValidateModelSerializer(data={'renamed': ''})
|
|
assert serializer.is_valid() is False
|
|
assert 'renamed' in serializer.errors
|
|
assert 'should_validate_field' not in serializer.errors
|
|
|
|
|
|
class TestCustomValidationMethods(TestCase):
|
|
def test_custom_validation_method_is_executed(self):
|
|
serializer = ShouldValidateModelSerializer(data={'renamed': 'fo'})
|
|
assert not serializer.is_valid()
|
|
assert 'renamed' in serializer.errors
|
|
|
|
def test_custom_validation_method_passing(self):
|
|
serializer = ShouldValidateModelSerializer(data={'renamed': 'foo'})
|
|
assert serializer.is_valid()
|
|
|
|
|
|
class ValidationSerializer(serializers.Serializer):
|
|
foo = serializers.CharField()
|
|
|
|
def validate_foo(self, attrs, source):
|
|
raise serializers.ValidationError("foo invalid")
|
|
|
|
def validate(self, attrs):
|
|
raise serializers.ValidationError("serializer invalid")
|
|
|
|
|
|
class TestAvoidValidation(TestCase):
|
|
"""
|
|
If serializer was initialized with invalid data (None or non dict-like), it
|
|
should avoid validation layer (validate_<field> and validate methods)
|
|
"""
|
|
def test_serializer_errors_has_only_invalid_data_error(self):
|
|
serializer = ValidationSerializer(data='invalid data')
|
|
assert not serializer.is_valid()
|
|
assert serializer.errors == {
|
|
'non_field_errors': [
|
|
'Invalid data. Expected a dictionary, but got %s.' % six.text_type.__name__
|
|
]
|
|
}
|
|
|
|
|
|
# regression tests for issue: 1493
|
|
|
|
class ValidationMaxValueValidatorModel(models.Model):
|
|
number_value = models.PositiveIntegerField(validators=[MaxValueValidator(100)])
|
|
|
|
|
|
class ValidationMaxValueValidatorModelSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = ValidationMaxValueValidatorModel
|
|
fields = '__all__'
|
|
|
|
|
|
class UpdateMaxValueValidationModel(generics.RetrieveUpdateDestroyAPIView):
|
|
queryset = ValidationMaxValueValidatorModel.objects.all()
|
|
serializer_class = ValidationMaxValueValidatorModelSerializer
|
|
|
|
|
|
class TestMaxValueValidatorValidation(TestCase):
|
|
|
|
def test_max_value_validation_serializer_success(self):
|
|
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 99})
|
|
assert serializer.is_valid()
|
|
|
|
def test_max_value_validation_serializer_fails(self):
|
|
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 101})
|
|
assert not serializer.is_valid()
|
|
assert serializer.errors == {
|
|
'number_value': [
|
|
'Ensure this value is less than or equal to 100.'
|
|
]
|
|
}
|
|
|
|
def test_max_value_validation_success(self):
|
|
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
|
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 98}, format='json')
|
|
view = UpdateMaxValueValidationModel().as_view()
|
|
response = view(request, pk=obj.pk).render()
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
def test_max_value_validation_fail(self):
|
|
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
|
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json')
|
|
view = UpdateMaxValueValidationModel().as_view()
|
|
response = view(request, pk=obj.pk).render()
|
|
assert response.content == b'{"number_value":["Ensure this value is less than or equal to 100."]}'
|
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
|
|
|
|
|
# regression tests for issue: 1533
|
|
|
|
class TestChoiceFieldChoicesValidate(TestCase):
|
|
CHOICES = [
|
|
(0, 'Small'),
|
|
(1, 'Medium'),
|
|
(2, 'Large'),
|
|
]
|
|
|
|
SINGLE_CHOICES = [0, 1, 2]
|
|
|
|
CHOICES_NESTED = [
|
|
('Category', (
|
|
(1, 'First'),
|
|
(2, 'Second'),
|
|
(3, 'Third'),
|
|
)),
|
|
(4, 'Fourth'),
|
|
]
|
|
|
|
MIXED_CHOICES = [
|
|
('Category', (
|
|
(1, 'First'),
|
|
(2, 'Second'),
|
|
)),
|
|
3,
|
|
(4, 'Fourth'),
|
|
]
|
|
|
|
def test_choices(self):
|
|
"""
|
|
Make sure a value for choices works as expected.
|
|
"""
|
|
f = serializers.ChoiceField(choices=self.CHOICES)
|
|
value = self.CHOICES[0][0]
|
|
try:
|
|
f.to_internal_value(value)
|
|
except serializers.ValidationError:
|
|
self.fail("Value %s does not validate" % str(value))
|
|
|
|
def test_single_choices(self):
|
|
"""
|
|
Make sure a single value for choices works as expected.
|
|
"""
|
|
f = serializers.ChoiceField(choices=self.SINGLE_CHOICES)
|
|
value = self.SINGLE_CHOICES[0]
|
|
try:
|
|
f.to_internal_value(value)
|
|
except serializers.ValidationError:
|
|
self.fail("Value %s does not validate" % str(value))
|
|
|
|
def test_nested_choices(self):
|
|
"""
|
|
Make sure a nested value for choices works as expected.
|
|
"""
|
|
f = serializers.ChoiceField(choices=self.CHOICES_NESTED)
|
|
value = self.CHOICES_NESTED[0][1][0][0]
|
|
try:
|
|
f.to_internal_value(value)
|
|
except serializers.ValidationError:
|
|
self.fail("Value %s does not validate" % str(value))
|
|
|
|
def test_mixed_choices(self):
|
|
"""
|
|
Make sure mixed values for choices works as expected.
|
|
"""
|
|
f = serializers.ChoiceField(choices=self.MIXED_CHOICES)
|
|
value = self.MIXED_CHOICES[1]
|
|
try:
|
|
f.to_internal_value(value)
|
|
except serializers.ValidationError:
|
|
self.fail("Value %s does not validate" % str(value))
|
|
|
|
|
|
class RegexSerializer(serializers.Serializer):
|
|
pin = serializers.CharField(
|
|
validators=[RegexValidator(regex=re.compile('^[0-9]{4,6}$'),
|
|
message='A PIN is 4-6 digits')])
|
|
|
|
|
|
expected_repr = """
|
|
RegexSerializer():
|
|
pin = CharField(validators=[<django.core.validators.RegexValidator object>])
|
|
""".strip()
|
|
|
|
|
|
class TestRegexSerializer(TestCase):
|
|
def test_regex_repr(self):
|
|
serializer_repr = repr(RegexSerializer())
|
|
assert serializer_repr == expected_repr
|