Skip to content

Commit 24391db

Browse files
author
John Eskew
committed
Customize validators to defer error string evaluation.
1 parent bf0fbd5 commit 24391db

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

rest_framework/compat.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@
1111
import django
1212
from django.apps import apps
1313
from django.conf import settings
14-
from django.core.exceptions import ImproperlyConfigured
14+
from django.core.exceptions import ImproperlyConfigured, ValidationError
15+
from django.core.validators import \
16+
MaxLengthValidator as DjangoMaxLengthValidator
17+
from django.core.validators import MaxValueValidator as DjangoMaxValueValidator
18+
from django.core.validators import \
19+
MinLengthValidator as DjangoMinLengthValidator
20+
from django.core.validators import MinValueValidator as DjangoMinValueValidator
1521
from django.db import connection, models, transaction
1622
from django.template import Context, RequestContext, Template
1723
from django.utils import six
1824
from django.views.generic import View
1925

20-
2126
try:
2227
from django.urls import (
2328
NoReverseMatch, RegexURLPattern, RegexURLResolver, ResolverMatch, Resolver404, get_script_prefix, reverse, reverse_lazy, resolve
@@ -293,6 +298,22 @@ def pygments_css(style):
293298
except ImportError:
294299
DecimalValidator = None
295300

301+
class CustomValidatorMessage(object):
302+
def __init__(self, *args, **kwargs):
303+
self.message = kwargs.pop('message', self.message)
304+
super(CustomValidatorMessage, self).__init__(*args, **kwargs)
305+
306+
class MinValueValidator(CustomValidatorMessage, DjangoMinValueValidator):
307+
pass
308+
309+
class MaxValueValidator(CustomValidatorMessage, DjangoMaxValueValidator):
310+
pass
311+
312+
class MinLengthValidator(CustomValidatorMessage, DjangoMinLengthValidator):
313+
pass
314+
315+
class MaxLengthValidator(CustomValidatorMessage, DjangoMaxLengthValidator):
316+
pass
296317

297318
def set_rollback():
298319
if hasattr(transaction, 'set_rollback'):

rest_framework/fields.py

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
from django.core.exceptions import ValidationError as DjangoValidationError
1414
from django.core.exceptions import ObjectDoesNotExist
1515
from django.core.validators import (
16-
EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator,
17-
MinValueValidator, RegexValidator, URLValidator, ip_address_validators
16+
EmailValidator, RegexValidator, URLValidator, ip_address_validators
1817
)
1918
from django.forms import FilePathField as DjangoFilePathField
2019
from django.forms import ImageField as DjangoImageField
@@ -25,14 +24,16 @@
2524
from django.utils.duration import duration_string
2625
from django.utils.encoding import is_protected_type, smart_text
2726
from django.utils.formats import localize_input, sanitize_separators
27+
from django.utils.functional import lazy
2828
from django.utils.ipv6 import clean_ipv6_address
2929
from django.utils.timezone import utc
3030
from django.utils.translation import ugettext_lazy as _
3131

3232
from rest_framework import ISO_8601
3333
from rest_framework.compat import (
34-
InvalidTimeError, get_remote_field, unicode_repr, unicode_to_repr,
35-
value_from_object
34+
InvalidTimeError, MaxLengthValidator, MaxValueValidator,
35+
MinLengthValidator, MinValueValidator, get_remote_field, unicode_repr,
36+
unicode_to_repr, value_from_object
3637
)
3738
from rest_framework.exceptions import ErrorDetail, ValidationError
3839
from rest_framework.settings import api_settings
@@ -750,11 +751,17 @@ def __init__(self, **kwargs):
750751
self.min_length = kwargs.pop('min_length', None)
751752
super(CharField, self).__init__(**kwargs)
752753
if self.max_length is not None:
753-
message = self.error_messages['max_length'].format(max_length=self.max_length)
754-
self.validators.append(MaxLengthValidator(self.max_length, message=message))
754+
message = lazy(
755+
self.error_messages['max_length'].format,
756+
six.text_type)(max_length=self.max_length)
757+
self.validators.append(
758+
MaxLengthValidator(self.max_length, message=message))
755759
if self.min_length is not None:
756-
message = self.error_messages['min_length'].format(min_length=self.min_length)
757-
self.validators.append(MinLengthValidator(self.min_length, message=message))
760+
message = lazy(
761+
self.error_messages['min_length'].format,
762+
six.text_type)(min_length=self.min_length)
763+
self.validators.append(
764+
MinLengthValidator(self.min_length, message=message))
758765

759766
def run_validation(self, data=empty):
760767
# Test for the empty string here so that it does not get validated,
@@ -909,11 +916,17 @@ def __init__(self, **kwargs):
909916
self.min_value = kwargs.pop('min_value', None)
910917
super(IntegerField, self).__init__(**kwargs)
911918
if self.max_value is not None:
912-
message = self.error_messages['max_value'].format(max_value=self.max_value)
913-
self.validators.append(MaxValueValidator(self.max_value, message=message))
919+
message = lazy(
920+
self.error_messages['max_value'].format,
921+
six.text_type)(max_value=self.max_value)
922+
self.validators.append(
923+
MaxValueValidator(self.max_value, message=message))
914924
if self.min_value is not None:
915-
message = self.error_messages['min_value'].format(min_value=self.min_value)
916-
self.validators.append(MinValueValidator(self.min_value, message=message))
925+
message = lazy(
926+
self.error_messages['min_value'].format,
927+
six.text_type)(min_value=self.min_value)
928+
self.validators.append(
929+
MinValueValidator(self.min_value, message=message))
917930

918931
def to_internal_value(self, data):
919932
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
@@ -943,11 +956,17 @@ def __init__(self, **kwargs):
943956
self.min_value = kwargs.pop('min_value', None)
944957
super(FloatField, self).__init__(**kwargs)
945958
if self.max_value is not None:
946-
message = self.error_messages['max_value'].format(max_value=self.max_value)
947-
self.validators.append(MaxValueValidator(self.max_value, message=message))
959+
message = lazy(
960+
self.error_messages['max_value'].format,
961+
six.text_type)(max_value=self.max_value)
962+
self.validators.append(
963+
MaxValueValidator(self.max_value, message=message))
948964
if self.min_value is not None:
949-
message = self.error_messages['min_value'].format(min_value=self.min_value)
950-
self.validators.append(MinValueValidator(self.min_value, message=message))
965+
message = lazy(
966+
self.error_messages['min_value'].format,
967+
six.text_type)(min_value=self.min_value)
968+
self.validators.append(
969+
MinValueValidator(self.min_value, message=message))
951970

952971
def to_internal_value(self, data):
953972

@@ -996,11 +1015,17 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=
9961015
super(DecimalField, self).__init__(**kwargs)
9971016

9981017
if self.max_value is not None:
999-
message = self.error_messages['max_value'].format(max_value=self.max_value)
1000-
self.validators.append(MaxValueValidator(self.max_value, message=message))
1018+
message = lazy(
1019+
self.error_messages['max_value'].format,
1020+
six.text_type)(max_value=self.max_value)
1021+
self.validators.append(
1022+
MaxValueValidator(self.max_value, message=message))
10011023
if self.min_value is not None:
1002-
message = self.error_messages['min_value'].format(min_value=self.min_value)
1003-
self.validators.append(MinValueValidator(self.min_value, message=message))
1024+
message = lazy(
1025+
self.error_messages['min_value'].format,
1026+
six.text_type)(min_value=self.min_value)
1027+
self.validators.append(
1028+
MinValueValidator(self.min_value, message=message))
10041029

10051030
def to_internal_value(self, data):
10061031
"""
@@ -1797,8 +1822,11 @@ def __init__(self, model_field, **kwargs):
17971822
max_length = kwargs.pop('max_length', None)
17981823
super(ModelField, self).__init__(**kwargs)
17991824
if max_length is not None:
1800-
message = self.error_messages['max_length'].format(max_length=max_length)
1801-
self.validators.append(MaxLengthValidator(max_length, message=message))
1825+
message = lazy(
1826+
self.error_messages['max_length'].format,
1827+
six.text_type)(max_length=self.max_length)
1828+
self.validators.append(
1829+
MaxLengthValidator(self.max_length, message=message))
18021830

18031831
def to_internal_value(self, data):
18041832
rel = get_remote_field(self.model_field, default=None)

0 commit comments

Comments
 (0)