Commit 24391db4 by John Eskew

Customize validators to defer error string evaluation.

parent bf0fbd5d
...@@ -11,13 +11,18 @@ import inspect ...@@ -11,13 +11,18 @@ import inspect
import django import django
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.validators import \
MaxLengthValidator as DjangoMaxLengthValidator
from django.core.validators import MaxValueValidator as DjangoMaxValueValidator
from django.core.validators import \
MinLengthValidator as DjangoMinLengthValidator
from django.core.validators import MinValueValidator as DjangoMinValueValidator
from django.db import connection, models, transaction from django.db import connection, models, transaction
from django.template import Context, RequestContext, Template from django.template import Context, RequestContext, Template
from django.utils import six from django.utils import six
from django.views.generic import View from django.views.generic import View
try: try:
from django.urls import ( from django.urls import (
NoReverseMatch, RegexURLPattern, RegexURLResolver, ResolverMatch, Resolver404, get_script_prefix, reverse, reverse_lazy, resolve NoReverseMatch, RegexURLPattern, RegexURLResolver, ResolverMatch, Resolver404, get_script_prefix, reverse, reverse_lazy, resolve
...@@ -293,6 +298,22 @@ try: ...@@ -293,6 +298,22 @@ try:
except ImportError: except ImportError:
DecimalValidator = None DecimalValidator = None
class CustomValidatorMessage(object):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(CustomValidatorMessage, self).__init__(*args, **kwargs)
class MinValueValidator(CustomValidatorMessage, DjangoMinValueValidator):
pass
class MaxValueValidator(CustomValidatorMessage, DjangoMaxValueValidator):
pass
class MinLengthValidator(CustomValidatorMessage, DjangoMinLengthValidator):
pass
class MaxLengthValidator(CustomValidatorMessage, DjangoMaxLengthValidator):
pass
def set_rollback(): def set_rollback():
if hasattr(transaction, 'set_rollback'): if hasattr(transaction, 'set_rollback'):
......
...@@ -13,8 +13,7 @@ from django.conf import settings ...@@ -13,8 +13,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import ( from django.core.validators import (
EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, EmailValidator, RegexValidator, URLValidator, ip_address_validators
MinValueValidator, RegexValidator, URLValidator, ip_address_validators
) )
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
...@@ -25,14 +24,16 @@ from django.utils.dateparse import ( ...@@ -25,14 +24,16 @@ from django.utils.dateparse import (
from django.utils.duration import duration_string from django.utils.duration import duration_string
from django.utils.encoding import is_protected_type, smart_text from django.utils.encoding import is_protected_type, smart_text
from django.utils.formats import localize_input, sanitize_separators from django.utils.formats import localize_input, sanitize_separators
from django.utils.functional import lazy
from django.utils.ipv6 import clean_ipv6_address from django.utils.ipv6 import clean_ipv6_address
from django.utils.timezone import utc from django.utils.timezone import utc
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import ISO_8601 from rest_framework import ISO_8601
from rest_framework.compat import ( from rest_framework.compat import (
InvalidTimeError, get_remote_field, unicode_repr, unicode_to_repr, InvalidTimeError, MaxLengthValidator, MaxValueValidator,
value_from_object MinLengthValidator, MinValueValidator, get_remote_field, unicode_repr,
unicode_to_repr, value_from_object
) )
from rest_framework.exceptions import ErrorDetail, ValidationError from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
...@@ -750,11 +751,17 @@ class CharField(Field): ...@@ -750,11 +751,17 @@ class CharField(Field):
self.min_length = kwargs.pop('min_length', None) self.min_length = kwargs.pop('min_length', None)
super(CharField, self).__init__(**kwargs) super(CharField, self).__init__(**kwargs)
if self.max_length is not None: if self.max_length is not None:
message = self.error_messages['max_length'].format(max_length=self.max_length) message = lazy(
self.validators.append(MaxLengthValidator(self.max_length, message=message)) self.error_messages['max_length'].format,
six.text_type)(max_length=self.max_length)
self.validators.append(
MaxLengthValidator(self.max_length, message=message))
if self.min_length is not None: if self.min_length is not None:
message = self.error_messages['min_length'].format(min_length=self.min_length) message = lazy(
self.validators.append(MinLengthValidator(self.min_length, message=message)) self.error_messages['min_length'].format,
six.text_type)(min_length=self.min_length)
self.validators.append(
MinLengthValidator(self.min_length, message=message))
def run_validation(self, data=empty): def run_validation(self, data=empty):
# Test for the empty string here so that it does not get validated, # Test for the empty string here so that it does not get validated,
...@@ -909,11 +916,17 @@ class IntegerField(Field): ...@@ -909,11 +916,17 @@ class IntegerField(Field):
self.min_value = kwargs.pop('min_value', None) self.min_value = kwargs.pop('min_value', None)
super(IntegerField, self).__init__(**kwargs) super(IntegerField, self).__init__(**kwargs)
if self.max_value is not None: if self.max_value is not None:
message = self.error_messages['max_value'].format(max_value=self.max_value) message = lazy(
self.validators.append(MaxValueValidator(self.max_value, message=message)) self.error_messages['max_value'].format,
six.text_type)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None: if self.min_value is not None:
message = self.error_messages['min_value'].format(min_value=self.min_value) message = lazy(
self.validators.append(MinValueValidator(self.min_value, message=message)) self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data): def to_internal_value(self, data):
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH: if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
...@@ -943,11 +956,17 @@ class FloatField(Field): ...@@ -943,11 +956,17 @@ class FloatField(Field):
self.min_value = kwargs.pop('min_value', None) self.min_value = kwargs.pop('min_value', None)
super(FloatField, self).__init__(**kwargs) super(FloatField, self).__init__(**kwargs)
if self.max_value is not None: if self.max_value is not None:
message = self.error_messages['max_value'].format(max_value=self.max_value) message = lazy(
self.validators.append(MaxValueValidator(self.max_value, message=message)) self.error_messages['max_value'].format,
six.text_type)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None: if self.min_value is not None:
message = self.error_messages['min_value'].format(min_value=self.min_value) message = lazy(
self.validators.append(MinValueValidator(self.min_value, message=message)) self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data): def to_internal_value(self, data):
...@@ -996,11 +1015,17 @@ class DecimalField(Field): ...@@ -996,11 +1015,17 @@ class DecimalField(Field):
super(DecimalField, self).__init__(**kwargs) super(DecimalField, self).__init__(**kwargs)
if self.max_value is not None: if self.max_value is not None:
message = self.error_messages['max_value'].format(max_value=self.max_value) message = lazy(
self.validators.append(MaxValueValidator(self.max_value, message=message)) self.error_messages['max_value'].format,
six.text_type)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None: if self.min_value is not None:
message = self.error_messages['min_value'].format(min_value=self.min_value) message = lazy(
self.validators.append(MinValueValidator(self.min_value, message=message)) self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data): def to_internal_value(self, data):
""" """
...@@ -1797,8 +1822,11 @@ class ModelField(Field): ...@@ -1797,8 +1822,11 @@ class ModelField(Field):
max_length = kwargs.pop('max_length', None) max_length = kwargs.pop('max_length', None)
super(ModelField, self).__init__(**kwargs) super(ModelField, self).__init__(**kwargs)
if max_length is not None: if max_length is not None:
message = self.error_messages['max_length'].format(max_length=max_length) message = lazy(
self.validators.append(MaxLengthValidator(max_length, message=message)) self.error_messages['max_length'].format,
six.text_type)(max_length=self.max_length)
self.validators.append(
MaxLengthValidator(self.max_length, message=message))
def to_internal_value(self, data): def to_internal_value(self, data):
rel = get_remote_field(self.model_field, default=None) rel = get_remote_field(self.model_field, default=None)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment