mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-05 04:50:12 +03:00
Update default error messages for translations
Make use of already translated strings in Django, wherever possible and makes sense.
This commit is contained in:
parent
6d8a652ef6
commit
f076caebb0
|
@ -491,7 +491,7 @@ As an example, let's create a field that can be used represent the class name of
|
|||
# We pass the object instance onto `to_representation`,
|
||||
# not just the field attribute.
|
||||
return obj
|
||||
|
||||
|
||||
def to_representation(self, obj):
|
||||
"""
|
||||
Serialize the object's class name.
|
||||
|
@ -522,7 +522,7 @@ To indicate invalid data, we should raise a `serializers.ValidationError`, like
|
|||
The `.fail()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example:
|
||||
|
||||
default_error_messages = {
|
||||
'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',
|
||||
'incorrect_type': 'Incorrect type. Expected a string, but got %(input_type)s',
|
||||
'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.',
|
||||
'out_of_range': 'Value out of range. Must be between 0 and 255.'
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.forms import ImageField as DjangoImageField
|
|||
from django.utils import six, timezone
|
||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||
from django.utils.encoding import is_protected_type, smart_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy, ugettext_lazy as _
|
||||
from rest_framework import ISO_8601
|
||||
from rest_framework.compat import (
|
||||
EmailValidator, MinValueValidator, MaxValueValidator,
|
||||
|
@ -147,7 +147,7 @@ class Field(object):
|
|||
|
||||
default_error_messages = {
|
||||
'required': _('This field is required.'),
|
||||
'null': _('This field may not be null.')
|
||||
'null': _('This field cannot be null.')
|
||||
}
|
||||
default_validators = []
|
||||
default_empty_html = empty
|
||||
|
@ -369,7 +369,7 @@ class Field(object):
|
|||
class_name = self.__class__.__name__
|
||||
msg = MISSING_ERROR_MESSAGE.format(class_name=class_name, key=key)
|
||||
raise AssertionError(msg)
|
||||
message_string = msg.format(**kwargs)
|
||||
message_string = msg % kwargs
|
||||
raise ValidationError(message_string)
|
||||
|
||||
@property
|
||||
|
@ -429,7 +429,7 @@ class Field(object):
|
|||
|
||||
class BooleanField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('`{input}` is not a valid boolean.')
|
||||
'invalid': _('`%(input)s` is not a valid boolean.')
|
||||
}
|
||||
default_empty_html = False
|
||||
initial = False
|
||||
|
@ -457,7 +457,7 @@ class BooleanField(Field):
|
|||
|
||||
class NullBooleanField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('`{input}` is not a valid boolean.')
|
||||
'invalid': _('`%(input)s` is not a valid boolean.')
|
||||
}
|
||||
initial = None
|
||||
TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))
|
||||
|
@ -492,9 +492,15 @@ class NullBooleanField(Field):
|
|||
|
||||
class CharField(Field):
|
||||
default_error_messages = {
|
||||
'blank': _('This field may not be blank.'),
|
||||
'max_length': _('Ensure this field has no more than {max_length} characters.'),
|
||||
'min_length': _('Ensure this field has no more than {min_length} characters.')
|
||||
'blank': _('This field cannot be blank.'),
|
||||
'max_length': ungettext_lazy(
|
||||
'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).',
|
||||
'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).',
|
||||
'limit_value'),
|
||||
'min_length': ungettext_lazy(
|
||||
'Ensure this value has at least %(limit_value)d character (it has %(show_value)d).',
|
||||
'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).',
|
||||
'limit_value')
|
||||
}
|
||||
initial = ''
|
||||
coerce_blank_to_null = False
|
||||
|
@ -502,15 +508,9 @@ class CharField(Field):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
self.allow_blank = kwargs.pop('allow_blank', False)
|
||||
max_length = kwargs.pop('max_length', None)
|
||||
min_length = kwargs.pop('min_length', None)
|
||||
self.max_length = kwargs.pop('max_length', None)
|
||||
self.min_length = kwargs.pop('min_length', None)
|
||||
super(CharField, self).__init__(**kwargs)
|
||||
if max_length is not None:
|
||||
message = self.error_messages['max_length'].format(max_length=max_length)
|
||||
self.validators.append(MaxLengthValidator(max_length, message=message))
|
||||
if min_length is not None:
|
||||
message = self.error_messages['min_length'].format(min_length=min_length)
|
||||
self.validators.append(MinLengthValidator(min_length, message=message))
|
||||
|
||||
def run_validation(self, data=empty):
|
||||
# Test for the empty string here so that it does not get validated,
|
||||
|
@ -520,6 +520,17 @@ class CharField(Field):
|
|||
if not self.allow_blank:
|
||||
self.fail('blank')
|
||||
return ''
|
||||
|
||||
if self.max_length is not None:
|
||||
params = {'limit_value': self.max_length, 'show_value': data}
|
||||
message = self.error_messages['max_length'] % params
|
||||
self.validators.append(MaxLengthValidator(self.max_length, message=message))
|
||||
|
||||
if self.min_length is not None:
|
||||
params = {'limit_value': self.min_length, 'show_value': data}
|
||||
message = self.error_messages['min_length'] % params
|
||||
self.validators.append(MinLengthValidator(self.min_length, message=message))
|
||||
|
||||
return super(CharField, self).run_validation(data)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
|
@ -571,7 +582,7 @@ class SlugField(CharField):
|
|||
|
||||
class URLField(CharField):
|
||||
default_error_messages = {
|
||||
'invalid': _("Enter a valid URL.")
|
||||
'invalid': _('Enter a valid URL.')
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -585,8 +596,8 @@ class URLField(CharField):
|
|||
class IntegerField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('A valid integer is required.'),
|
||||
'max_value': _('Ensure this value is less than or equal to {max_value}.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
|
||||
'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
|
||||
'max_string_length': _('String value too large')
|
||||
}
|
||||
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
|
||||
|
@ -596,10 +607,10 @@ class IntegerField(Field):
|
|||
min_value = kwargs.pop('min_value', None)
|
||||
super(IntegerField, self).__init__(**kwargs)
|
||||
if max_value is not None:
|
||||
message = self.error_messages['max_value'].format(max_value=max_value)
|
||||
message = self.error_messages['max_value'] % {'limit_value': max_value}
|
||||
self.validators.append(MaxValueValidator(max_value, message=message))
|
||||
if min_value is not None:
|
||||
message = self.error_messages['min_value'].format(min_value=min_value)
|
||||
message = self.error_messages['min_value'] % {'limit_value': min_value}
|
||||
self.validators.append(MinValueValidator(min_value, message=message))
|
||||
|
||||
def to_internal_value(self, data):
|
||||
|
@ -618,9 +629,9 @@ class IntegerField(Field):
|
|||
|
||||
class FloatField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _("A valid number is required."),
|
||||
'max_value': _('Ensure this value is less than or equal to {max_value}.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
|
||||
'invalid': _('A valid number is required.'),
|
||||
'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
|
||||
'max_string_length': _('String value too large')
|
||||
}
|
||||
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
|
||||
|
@ -630,10 +641,12 @@ class FloatField(Field):
|
|||
min_value = kwargs.pop('min_value', None)
|
||||
super(FloatField, self).__init__(**kwargs)
|
||||
if max_value is not None:
|
||||
message = self.error_messages['max_value'].format(max_value=max_value)
|
||||
params = {'limit_value': max_value}
|
||||
message = self.error_messages['max_value'] % params
|
||||
self.validators.append(MaxValueValidator(max_value, message=message))
|
||||
if min_value is not None:
|
||||
message = self.error_messages['min_value'].format(min_value=min_value)
|
||||
params = {'limit_value': min_value}
|
||||
message = self.error_messages['min_value'] % params
|
||||
self.validators.append(MinValueValidator(min_value, message=message))
|
||||
|
||||
def to_internal_value(self, data):
|
||||
|
@ -652,11 +665,20 @@ class FloatField(Field):
|
|||
class DecimalField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('A valid number is required.'),
|
||||
'max_value': _('Ensure this value is less than or equal to {max_value}.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
|
||||
'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'),
|
||||
'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'),
|
||||
'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'),
|
||||
'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
|
||||
'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
|
||||
'max_digits': ungettext_lazy(
|
||||
'Ensure that there are no more than %(max)s digit in total.',
|
||||
'Ensure that there are no more than %(max)s digits in total.',
|
||||
'max'),
|
||||
'max_decimal_places': ungettext_lazy(
|
||||
'Ensure that there are no more than %(max)s decimal place.',
|
||||
'Ensure that there are no more than %(max)s decimal places.',
|
||||
'max'),
|
||||
'max_whole_digits': ungettext_lazy(
|
||||
'Ensure that there are no more than %(max)s digit before the decimal point.',
|
||||
'Ensure that there are no more than %(max)s digits before the decimal point.',
|
||||
'max'),
|
||||
'max_string_length': _('String value too large')
|
||||
}
|
||||
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
|
||||
|
@ -669,10 +691,12 @@ class DecimalField(Field):
|
|||
self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string
|
||||
super(DecimalField, self).__init__(**kwargs)
|
||||
if max_value is not None:
|
||||
message = self.error_messages['max_value'].format(max_value=max_value)
|
||||
params = {'limit_value': max_value}
|
||||
message = self.error_messages['max_value'] % params
|
||||
self.validators.append(MaxValueValidator(max_value, message=message))
|
||||
if min_value is not None:
|
||||
message = self.error_messages['min_value'].format(min_value=min_value)
|
||||
params = {'limit_value': min_value}
|
||||
message = self.error_messages['min_value'] % params
|
||||
self.validators.append(MinValueValidator(min_value, message=message))
|
||||
|
||||
def to_internal_value(self, data):
|
||||
|
@ -713,11 +737,11 @@ class DecimalField(Field):
|
|||
whole_digits = digits - decimals
|
||||
|
||||
if self.max_digits is not None and digits > self.max_digits:
|
||||
self.fail('max_digits', max_digits=self.max_digits)
|
||||
self.fail('max_digits', max=self.max_digits)
|
||||
if self.decimal_places is not None and decimals > self.decimal_places:
|
||||
self.fail('max_decimal_places', max_decimal_places=self.decimal_places)
|
||||
self.fail('max_decimal_places', max=self.decimal_places)
|
||||
if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places):
|
||||
self.fail('max_whole_digits', max_whole_digits=self.max_digits - self.decimal_places)
|
||||
self.fail('max_whole_digits', max=self.max_digits - self.decimal_places)
|
||||
|
||||
return value
|
||||
|
||||
|
@ -740,7 +764,7 @@ class DecimalField(Field):
|
|||
|
||||
class DateTimeField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}'),
|
||||
'invalid': _('Datetime has wrong format. Use one of these formats instead: %(format)s'),
|
||||
'date': _('Expected a datetime but got a date.'),
|
||||
}
|
||||
format = api_settings.DATETIME_FORMAT
|
||||
|
@ -805,7 +829,7 @@ class DateTimeField(Field):
|
|||
|
||||
class DateField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('Date has wrong format. Use one of these formats instead: {format}'),
|
||||
'invalid': _('Date has wrong format. Use one of these formats instead: %(format)s'),
|
||||
'datetime': _('Expected a date but got a datetime.'),
|
||||
}
|
||||
format = api_settings.DATE_FORMAT
|
||||
|
@ -863,7 +887,7 @@ class DateField(Field):
|
|||
|
||||
class TimeField(Field):
|
||||
default_error_messages = {
|
||||
'invalid': _('Time has wrong format. Use one of these formats instead: {format}'),
|
||||
'invalid': _('Time has wrong format. Use one of these formats instead: %(format)s'),
|
||||
}
|
||||
format = api_settings.TIME_FORMAT
|
||||
input_formats = api_settings.TIME_INPUT_FORMATS
|
||||
|
@ -919,7 +943,7 @@ class TimeField(Field):
|
|||
|
||||
class ChoiceField(Field):
|
||||
default_error_messages = {
|
||||
'invalid_choice': _('`{input}` is not a valid choice.')
|
||||
'invalid_choice': _('Value %(value)r is not a valid choice.')
|
||||
}
|
||||
|
||||
def __init__(self, choices, **kwargs):
|
||||
|
@ -948,7 +972,7 @@ class ChoiceField(Field):
|
|||
try:
|
||||
return self.choice_strings_to_values[six.text_type(data)]
|
||||
except KeyError:
|
||||
self.fail('invalid_choice', input=data)
|
||||
self.fail('invalid_choice', value=data)
|
||||
|
||||
def to_representation(self, value):
|
||||
if value in ('', None):
|
||||
|
@ -958,8 +982,8 @@ class ChoiceField(Field):
|
|||
|
||||
class MultipleChoiceField(ChoiceField):
|
||||
default_error_messages = {
|
||||
'invalid_choice': _('`{input}` is not a valid choice.'),
|
||||
'not_a_list': _('Expected a list of items but got type `{input_type}`.')
|
||||
'invalid_choice': _('Value %(value)r is not a valid choice.'),
|
||||
'not_a_list': _('Expected a list of items but got type `%(input_type)s`.')
|
||||
}
|
||||
default_empty_html = []
|
||||
|
||||
|
@ -989,11 +1013,14 @@ class MultipleChoiceField(ChoiceField):
|
|||
|
||||
class FileField(Field):
|
||||
default_error_messages = {
|
||||
'required': _("No file was submitted."),
|
||||
'invalid': _("The submitted data was not a file. Check the encoding type on the form."),
|
||||
'no_name': _("No filename could be determined."),
|
||||
'empty': _("The submitted file is empty."),
|
||||
'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'),
|
||||
'required': _('No file was submitted.'),
|
||||
'invalid': _('The submitted data was not a file. Check the encoding type on the form.'),
|
||||
'no_name': _('No filename could be determined.'),
|
||||
'empty': _('The submitted file is empty.'),
|
||||
'max_length': ungettext_lazy(
|
||||
'Ensure this filename has at most %(max)d character (it has %(length)d).',
|
||||
'Ensure this filename has at most %(max)d characters (it has %(length)d).',
|
||||
'max'),
|
||||
}
|
||||
use_url = api_settings.UPLOADED_FILES_USE_URL
|
||||
|
||||
|
@ -1016,7 +1043,7 @@ class FileField(Field):
|
|||
if not self.allow_empty_file and not file_size:
|
||||
self.fail('empty')
|
||||
if self.max_length and len(file_name) > self.max_length:
|
||||
self.fail('max_length', max_length=self.max_length, length=len(file_name))
|
||||
self.fail('max_length', max=self.max_length, length=len(file_name))
|
||||
|
||||
return data
|
||||
|
||||
|
@ -1061,7 +1088,7 @@ class ListField(Field):
|
|||
child = None
|
||||
initial = []
|
||||
default_error_messages = {
|
||||
'not_a_list': _('Expected a list of items but got type `{input_type}`')
|
||||
'not_a_list': _('Expected a list of items but got type `%(input_type)s`')
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -1192,18 +1219,26 @@ class ModelField(Field):
|
|||
that do not have a serializer field to be mapped to.
|
||||
"""
|
||||
default_error_messages = {
|
||||
'max_length': _('Ensure this field has no more than {max_length} characters.'),
|
||||
'max_length': ungettext_lazy(
|
||||
'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).',
|
||||
'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).',
|
||||
'limit_value'),
|
||||
}
|
||||
|
||||
def __init__(self, model_field, **kwargs):
|
||||
self.model_field = model_field
|
||||
# The `max_length` option is supported by Django's base `Field` class,
|
||||
# so we'd better support it here.
|
||||
max_length = kwargs.pop('max_length', None)
|
||||
self.max_length = kwargs.pop('max_length', None)
|
||||
super(ModelField, self).__init__(**kwargs)
|
||||
if max_length is not None:
|
||||
message = self.error_messages['max_length'].format(max_length=max_length)
|
||||
self.validators.append(MaxLengthValidator(max_length, message=message))
|
||||
|
||||
def run_validation(self, data=empty):
|
||||
if self.max_length is not None:
|
||||
params = {'limit_value': self.max_length, 'show_value': data}
|
||||
message = self.error_messages['max_length'] % params
|
||||
self.validators.append(MaxLengthValidator(self.max_length, message=message))
|
||||
|
||||
return super(ModelField, self).run_validation(data)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
rel = getattr(self.model_field, 'rel', None)
|
||||
|
|
|
@ -116,8 +116,8 @@ class StringRelatedField(RelatedField):
|
|||
class PrimaryKeyRelatedField(RelatedField):
|
||||
default_error_messages = {
|
||||
'required': 'This field is required.',
|
||||
'does_not_exist': "Invalid pk '{pk_value}' - object does not exist.",
|
||||
'incorrect_type': 'Incorrect type. Expected pk value, received {data_type}.',
|
||||
'does_not_exist': "Invalid pk '%(pk_value)s' - object does not exist.",
|
||||
'incorrect_type': 'Incorrect type. Expected pk value, received %(data_type)s.',
|
||||
}
|
||||
|
||||
def to_internal_value(self, data):
|
||||
|
@ -166,7 +166,7 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
'no_match': 'Invalid hyperlink - No URL match',
|
||||
'incorrect_match': 'Invalid hyperlink - Incorrect URL match.',
|
||||
'does_not_exist': 'Invalid hyperlink - Object does not exist.',
|
||||
'incorrect_type': 'Incorrect type. Expected URL string, received {data_type}.',
|
||||
'incorrect_type': 'Incorrect type. Expected URL string, received %(data_type)s.',
|
||||
}
|
||||
|
||||
def __init__(self, view_name=None, **kwargs):
|
||||
|
@ -293,7 +293,7 @@ class SlugRelatedField(RelatedField):
|
|||
"""
|
||||
|
||||
default_error_messages = {
|
||||
'does_not_exist': _("Object with {slug_name}={value} does not exist."),
|
||||
'does_not_exist': _("Object with %(slug_name)s=%(value)s does not exist."),
|
||||
'invalid': _('Invalid value.'),
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestSimpleBoundField:
|
|||
serializer.is_valid()
|
||||
|
||||
assert serializer['text'].value == 'x' * 1000
|
||||
assert serializer['text'].errors == ['Ensure this field has no more than 100 characters.']
|
||||
assert serializer['text'].errors == ['Ensure this value has at most 100 characters (it has 1000).']
|
||||
assert serializer['text'].name == 'text'
|
||||
assert serializer['amount'].value is 123
|
||||
assert serializer['amount'].errors is None
|
||||
|
|
|
@ -49,7 +49,7 @@ class TestEmpty:
|
|||
field = serializers.IntegerField()
|
||||
with pytest.raises(serializers.ValidationError) as exc_info:
|
||||
field.run_validation(None)
|
||||
assert exc_info.value.detail == ['This field may not be null.']
|
||||
assert exc_info.value.detail == ['This field cannot be null.']
|
||||
|
||||
def test_allow_null(self):
|
||||
"""
|
||||
|
@ -66,7 +66,7 @@ class TestEmpty:
|
|||
field = serializers.CharField()
|
||||
with pytest.raises(serializers.ValidationError) as exc_info:
|
||||
field.run_validation('')
|
||||
assert exc_info.value.detail == ['This field may not be blank.']
|
||||
assert exc_info.value.detail == ['This field cannot be blank.']
|
||||
|
||||
def test_allow_blank(self):
|
||||
"""
|
||||
|
@ -290,6 +290,24 @@ class FieldValues:
|
|||
for output_value, expected_output in get_items(self.outputs):
|
||||
assert self.field.to_representation(output_value) == expected_output
|
||||
|
||||
@override_settings(LANGUAGE_CODE='es')
|
||||
def test_invalid_inputs_translated(self):
|
||||
"""
|
||||
Ensure that invalid values raise the expected validation localized error.
|
||||
"""
|
||||
es_invalid_inputs = get_items(getattr(self, 'es_invalid_inputs', {}))
|
||||
|
||||
if not es_invalid_inputs:
|
||||
return
|
||||
|
||||
field_kwargs = getattr(self, 'field_kwargs', {})
|
||||
field = self.field.__class__(**field_kwargs)
|
||||
|
||||
for input_value, expected_failure in es_invalid_inputs:
|
||||
with pytest.raises(serializers.ValidationError) as exc_info:
|
||||
field.run_validation(input_value)
|
||||
assert exc_info.value.detail == expected_failure
|
||||
|
||||
|
||||
# Boolean types...
|
||||
|
||||
|
@ -309,7 +327,11 @@ class TestBooleanField(FieldValues):
|
|||
}
|
||||
invalid_inputs = {
|
||||
'foo': ['`foo` is not a valid boolean.'],
|
||||
None: ['This field may not be null.']
|
||||
None: ['This field cannot be null.']
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'foo': ['`foo` is not a valid boolean.'],
|
||||
None: ['Este campo no puede ser nulo.']
|
||||
}
|
||||
outputs = {
|
||||
'true': True,
|
||||
|
@ -363,7 +385,10 @@ class TestCharField(FieldValues):
|
|||
'abc': 'abc'
|
||||
}
|
||||
invalid_inputs = {
|
||||
'': ['This field may not be blank.']
|
||||
'': ['This field cannot be blank.']
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'': [u'Este campo no puede estar vacío.']
|
||||
}
|
||||
outputs = {
|
||||
1: '1',
|
||||
|
@ -383,6 +408,9 @@ class TestEmailField(FieldValues):
|
|||
invalid_inputs = {
|
||||
'examplecom': ['Enter a valid email address.']
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'examplecom': [u'Introduzca una dirección de correo electrónico válida.']
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.EmailField()
|
||||
|
||||
|
@ -398,7 +426,8 @@ class TestRegexField(FieldValues):
|
|||
'A9': ["This value does not match the required pattern."]
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.RegexField(regex='[a-z][0-9]')
|
||||
field_kwargs = {'regex': '[a-z][0-9]'}
|
||||
field = serializers.RegexField(**field_kwargs)
|
||||
|
||||
|
||||
class TestSlugField(FieldValues):
|
||||
|
@ -411,6 +440,9 @@ class TestSlugField(FieldValues):
|
|||
invalid_inputs = {
|
||||
'slug 99': ["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."]
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'slug 99': [u"Introduzca un 'slug' válido, consistente en letras, números, guiones bajos o medios."]
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.SlugField()
|
||||
|
||||
|
@ -425,6 +457,9 @@ class TestURLField(FieldValues):
|
|||
invalid_inputs = {
|
||||
'example.com': ['Enter a valid URL.']
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'example.com': [u'Introduzca una URL válida.']
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.URLField()
|
||||
|
||||
|
@ -446,6 +481,9 @@ class TestIntegerField(FieldValues):
|
|||
invalid_inputs = {
|
||||
'abc': ['A valid integer is required.']
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'abc': ['A valid integer is required.']
|
||||
}
|
||||
outputs = {
|
||||
'1': 1,
|
||||
'0': 0,
|
||||
|
@ -480,18 +518,11 @@ class TestMinMaxIntegerField(FieldValues):
|
|||
'4': [u'Asegúrese de que este valor es menor o igual a 3.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.IntegerField(min_value=1, max_value=3)
|
||||
|
||||
@override_settings(LANGUAGE_CODE='es')
|
||||
def test_invalid_inputs_translated(self):
|
||||
"""
|
||||
Ensure that invalid values raise the expected validation error.
|
||||
"""
|
||||
field = serializers.IntegerField(min_value=1, max_value=3)
|
||||
for input_value, expected_failure in get_items(self.es_invalid_inputs):
|
||||
with pytest.raises(serializers.ValidationError) as exc_info:
|
||||
field.run_validation(input_value)
|
||||
assert exc_info.value.detail == expected_failure
|
||||
field_kwargs = {
|
||||
'min_value': 1,
|
||||
'max_value': 3,
|
||||
}
|
||||
field = serializers.IntegerField(**field_kwargs)
|
||||
|
||||
|
||||
class TestFloatField(FieldValues):
|
||||
|
@ -509,6 +540,9 @@ class TestFloatField(FieldValues):
|
|||
invalid_inputs = {
|
||||
'abc': ["A valid number is required."]
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'abc': ['A valid number is required.']
|
||||
}
|
||||
outputs = {
|
||||
'1': 1.0,
|
||||
'0': 0.0,
|
||||
|
@ -538,8 +572,15 @@ class TestMinMaxFloatField(FieldValues):
|
|||
'0.0': ['Ensure this value is greater than or equal to 1.'],
|
||||
'3.1': ['Ensure this value is less than or equal to 3.'],
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
0.9: [u'Asegúrese de que este valor es mayor o igual a 1.'],
|
||||
3.1: [u'Asegúrese de que este valor es menor o igual a 3.'],
|
||||
'0.0': [u'Asegúrese de que este valor es mayor o igual a 1.'],
|
||||
'3.1': [u'Asegúrese de que este valor es menor o igual a 3.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.FloatField(min_value=1, max_value=3)
|
||||
field_kwargs = {'min_value': 1, 'max_value': 3}
|
||||
field = serializers.FloatField(**field_kwargs)
|
||||
|
||||
|
||||
class TestDecimalField(FieldValues):
|
||||
|
@ -559,9 +600,17 @@ class TestDecimalField(FieldValues):
|
|||
(Decimal('Nan'), ["A valid number is required."]),
|
||||
(Decimal('Inf'), ["A valid number is required."]),
|
||||
('12.345', ["Ensure that there are no more than 3 digits in total."]),
|
||||
('0.01', ["Ensure that there are no more than 1 decimal places."]),
|
||||
('0.01', ["Ensure that there are no more than 1 decimal place."]),
|
||||
(123, ["Ensure that there are no more than 2 digits before the decimal point."])
|
||||
)
|
||||
es_invalid_inputs = (
|
||||
('abc', ["A valid number is required."]),
|
||||
(Decimal('Nan'), ["A valid number is required."]),
|
||||
(Decimal('Inf'), ["A valid number is required."]),
|
||||
('12.345', [u'Asegúrese de que no hay más de 3 dígitos en total.']),
|
||||
('0.01', [u'Asegúrese de que no haya más de 1 dígito decimal.']),
|
||||
(123, [u'Asegúrese de que no haya más de 2 dígitos antes del punto decimal.'])
|
||||
)
|
||||
outputs = {
|
||||
'1': '1.0',
|
||||
'0': '0.0',
|
||||
|
@ -574,7 +623,8 @@ class TestDecimalField(FieldValues):
|
|||
Decimal('1.09'): '1.1',
|
||||
Decimal('0.04'): '0.0'
|
||||
}
|
||||
field = serializers.DecimalField(max_digits=3, decimal_places=1)
|
||||
field_kwargs = {'max_digits': 3, 'decimal_places': 1}
|
||||
field = serializers.DecimalField(**field_kwargs)
|
||||
|
||||
|
||||
class TestMinMaxDecimalField(FieldValues):
|
||||
|
@ -589,11 +639,16 @@ class TestMinMaxDecimalField(FieldValues):
|
|||
'9.9': ['Ensure this value is greater than or equal to 10.'],
|
||||
'20.1': ['Ensure this value is less than or equal to 20.'],
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'9.9': [u'Asegúrese de que este valor es mayor o igual a 10.'],
|
||||
'20.1': [u'Asegúrese de que este valor es menor o igual a 20.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.DecimalField(
|
||||
max_digits=3, decimal_places=1,
|
||||
min_value=10, max_value=20
|
||||
)
|
||||
field_kwargs = {
|
||||
'max_digits': 3, 'decimal_places': 1,
|
||||
'min_value': 10, 'max_value': 20
|
||||
}
|
||||
field = serializers.DecimalField(**field_kwargs)
|
||||
|
||||
|
||||
class TestNoStringCoercionDecimalField(FieldValues):
|
||||
|
@ -610,10 +665,11 @@ class TestNoStringCoercionDecimalField(FieldValues):
|
|||
Decimal('1.09'): Decimal('1.1'),
|
||||
Decimal('0.04'): Decimal('0.0'),
|
||||
}
|
||||
field = serializers.DecimalField(
|
||||
max_digits=3, decimal_places=1,
|
||||
coerce_to_string=False
|
||||
)
|
||||
field_kwargs = {
|
||||
'max_digits': 3, 'decimal_places': 1,
|
||||
'coerce_to_string': False
|
||||
}
|
||||
field = serializers.DecimalField(**field_kwargs)
|
||||
|
||||
|
||||
# Date & time serializers...
|
||||
|
@ -648,7 +704,8 @@ class TestCustomInputFormatDateField(FieldValues):
|
|||
'2001-01-01': ['Date has wrong format. Use one of these formats instead: DD [Jan-Dec] YYYY']
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.DateField(input_formats=['%d %b %Y'])
|
||||
field_kwargs = {'input_formats': ['%d %b %Y']}
|
||||
field = serializers.DateField(**field_kwargs)
|
||||
|
||||
|
||||
class TestCustomOutputFormatDateField(FieldValues):
|
||||
|
@ -819,19 +876,23 @@ class TestChoiceField(FieldValues):
|
|||
'good': 'good',
|
||||
}
|
||||
invalid_inputs = {
|
||||
'amazing': ['`amazing` is not a valid choice.']
|
||||
'amazing': ["Value 'amazing' is not a valid choice."]
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'amazing': [u"Valor 'amazing' no es una opción válida."]
|
||||
}
|
||||
outputs = {
|
||||
'good': 'good',
|
||||
'': ''
|
||||
}
|
||||
field = serializers.ChoiceField(
|
||||
choices=[
|
||||
field_kwargs = {
|
||||
'choices': [
|
||||
('poor', 'Poor quality'),
|
||||
('medium', 'Medium quality'),
|
||||
('good', 'Good quality'),
|
||||
]
|
||||
)
|
||||
}
|
||||
field = serializers.ChoiceField(**field_kwargs)
|
||||
|
||||
|
||||
class TestChoiceFieldWithType(FieldValues):
|
||||
|
@ -844,20 +905,25 @@ class TestChoiceFieldWithType(FieldValues):
|
|||
3: 3,
|
||||
}
|
||||
invalid_inputs = {
|
||||
5: ['`5` is not a valid choice.'],
|
||||
'abc': ['`abc` is not a valid choice.']
|
||||
5: ['Value 5 is not a valid choice.'],
|
||||
'abc': ["Value 'abc' is not a valid choice."]
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
5: [u'Valor 5 no es una opción válida.'],
|
||||
'abc': [u"Valor 'abc' no es una opción válida."]
|
||||
}
|
||||
outputs = {
|
||||
'1': 1,
|
||||
1: 1
|
||||
}
|
||||
field = serializers.ChoiceField(
|
||||
choices=[
|
||||
field_kwargs = {
|
||||
'choices': [
|
||||
(1, 'Poor quality'),
|
||||
(2, 'Medium quality'),
|
||||
(3, 'Good quality'),
|
||||
]
|
||||
)
|
||||
}
|
||||
field = serializers.ChoiceField(**field_kwargs)
|
||||
|
||||
|
||||
class TestChoiceFieldWithListChoices(FieldValues):
|
||||
|
@ -871,12 +937,16 @@ class TestChoiceFieldWithListChoices(FieldValues):
|
|||
'good': 'good',
|
||||
}
|
||||
invalid_inputs = {
|
||||
'awful': ['`awful` is not a valid choice.']
|
||||
'awful': ["Value 'awful' is not a valid choice."]
|
||||
}
|
||||
es_invalid_inputs = {
|
||||
'awful': [u"Valor 'awful' no es una opción válida."]
|
||||
}
|
||||
outputs = {
|
||||
'good': 'good'
|
||||
}
|
||||
field = serializers.ChoiceField(choices=('poor', 'medium', 'good'))
|
||||
field_kwargs = {'choices': ('poor', 'medium', 'good')}
|
||||
field = serializers.ChoiceField(**field_kwargs)
|
||||
|
||||
|
||||
class TestMultipleChoiceField(FieldValues):
|
||||
|
@ -890,18 +960,19 @@ class TestMultipleChoiceField(FieldValues):
|
|||
}
|
||||
invalid_inputs = {
|
||||
'abc': ['Expected a list of items but got type `str`.'],
|
||||
('aircon', 'incorrect'): ['`incorrect` is not a valid choice.']
|
||||
('aircon', 'incorrect'): ["Value 'incorrect' is not a valid choice."]
|
||||
}
|
||||
outputs = [
|
||||
(['aircon', 'manual'], set(['aircon', 'manual']))
|
||||
]
|
||||
field = serializers.MultipleChoiceField(
|
||||
choices=[
|
||||
field_kwargs = {
|
||||
'choices': [
|
||||
('aircon', 'AirCon'),
|
||||
('manual', 'Manual drive'),
|
||||
('diesel', 'Diesel'),
|
||||
]
|
||||
)
|
||||
}
|
||||
field = serializers.MultipleChoiceField(**field_kwargs)
|
||||
|
||||
|
||||
# File serializers...
|
||||
|
|
|
@ -302,7 +302,7 @@ class HyperlinkedForeignKeyTests(TestCase):
|
|||
instance = ForeignKeySource.objects.get(pk=1)
|
||||
serializer = ForeignKeySourceSerializer(instance, data=data, context={'request': request})
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertEqual(serializer.errors, {'target': ['This field may not be null.']})
|
||||
self.assertEqual(serializer.errors, {'target': ['This field cannot be null.']})
|
||||
|
||||
|
||||
class HyperlinkedNullableForeignKeyTests(TestCase):
|
||||
|
|
|
@ -282,7 +282,7 @@ class PKForeignKeyTests(TestCase):
|
|||
instance = ForeignKeySource.objects.get(pk=1)
|
||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertEqual(serializer.errors, {'target': ['This field may not be null.']})
|
||||
self.assertEqual(serializer.errors, {'target': ['This field cannot be null.']})
|
||||
|
||||
def test_foreign_key_with_empty(self):
|
||||
"""
|
||||
|
|
|
@ -160,7 +160,7 @@ class SlugForeignKeyTests(TestCase):
|
|||
instance = ForeignKeySource.objects.get(pk=1)
|
||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertEqual(serializer.errors, {'target': ['This field may not be null.']})
|
||||
self.assertEqual(serializer.errors, {'target': ['This field cannot be null.']})
|
||||
|
||||
|
||||
class SlugNullableForeignKeyTests(TestCase):
|
||||
|
|
Loading…
Reference in New Issue
Block a user