Fix failing copy of fields when RegexValidator is used. Closes #1954.

This commit is contained in:
Tom Christie 2014-11-05 10:48:30 +00:00
parent 26b6180f50
commit 0a5d088287
2 changed files with 31 additions and 5 deletions

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.core import validators
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.validators import RegexValidator
from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone
from django.utils.datastructures import SortedDict
@ -392,7 +392,15 @@ class Field(object):
originally created with, rather than copying the complete state.
"""
args = copy.deepcopy(self._args)
kwargs = copy.deepcopy(self._kwargs)
kwargs = dict(self._kwargs)
# Bit ugly, but we need to special case 'validators' as Django's
# RegexValidator does not support deepcopy.
# We treat validator callables as immutable objects.
# See https://github.com/tomchristie/django-rest-framework/issues/1954
validators = kwargs.pop('validators', None)
kwargs = copy.deepcopy(kwargs)
if validators is not None:
kwargs['validators'] = validators
return self.__class__(*args, **kwargs)
def __repr__(self):
@ -531,7 +539,7 @@ class RegexField(CharField):
def __init__(self, regex, **kwargs):
super(RegexField, self).__init__(**kwargs)
validator = validators.RegexValidator(regex, message=self.error_messages['invalid'])
validator = RegexValidator(regex, message=self.error_messages['invalid'])
self.validators.append(validator)
@ -543,7 +551,7 @@ class SlugField(CharField):
def __init__(self, **kwargs):
super(SlugField, self).__init__(**kwargs)
slug_regex = re.compile(r'^[-a-zA-Z0-9_]+$')
validator = validators.RegexValidator(slug_regex, message=self.error_messages['invalid'])
validator = RegexValidator(slug_regex, message=self.error_messages['invalid'])
self.validators.append(validator)

View File

@ -1,9 +1,10 @@
from __future__ import unicode_literals
from django.core.validators import MaxValueValidator
from django.core.validators import RegexValidator, MaxValueValidator
from django.db import models
from django.test import TestCase
from rest_framework import generics, serializers, status
from rest_framework.test import APIRequestFactory
import re
factory = APIRequestFactory()
@ -174,3 +175,20 @@ class TestChoiceFieldChoicesValidate(TestCase):
# f.to_native(value)
# except 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