From 86484668f689864aa54e127a8107bdee55240cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Gro=C3=9F?= Date: Tue, 20 Nov 2012 15:38:50 +0100 Subject: [PATCH 1/3] added RegexField --- docs/api-guide/fields.md | 10 ++++++++++ docs/topics/release-notes.md | 1 + rest_framework/fields.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 0485b158f..cb30a52e8 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -141,6 +141,16 @@ A text representation, validates the text to be a valid e-mail address. Corresponds to `django.db.models.fields.EmailField` +## RegexField + +A text representation, that validates the given value matches against a certain regular expression. + +Uses Django's `django.core.validators.RegexValidator` for validation. + +Corresponds to `django.forms.fields.RegexField` + +**Signature:** `RegexField(regex, max_length=None, min_length=None)` + ## DateField A date representation. diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 35e8a8b35..e4e676358 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -7,6 +7,7 @@ ## Master * Support for `read_only_fields` on `ModelSerializer` classes. +* Added `RegexField`. ## 2.1.2 diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 4c2064261..071746de3 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1,6 +1,7 @@ import copy import datetime import inspect +import re import warnings from django.core import validators @@ -768,6 +769,34 @@ class EmailField(CharField): return result +class RegexField(CharField): + type_name = 'RegexField' + + def __init__(self, regex, max_length=None, min_length=None, *args, **kwargs): + super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) + self.regex = regex + + def _get_regex(self): + return self._regex + + def _set_regex(self, regex): + if isinstance(regex, basestring): + regex = re.compile(regex) + self._regex = regex + if hasattr(self, '_regex_validator') and self._regex_validator in self.validators: + self.validators.remove(self._regex_validator) + self._regex_validator = validators.RegexValidator(regex=regex) + self.validators.append(self._regex_validator) + + regex = property(_get_regex, _set_regex) + + def __deepcopy__(self, memo): + result = copy.copy(self) + memo[id(self)] = result + result.validators = self.validators[:] + return result + + class DateField(WritableField): type_name = 'DateField' From ed713d0354b67bdc64de9346b9a72e1adfced76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Gro=C3=9F?= Date: Wed, 21 Nov 2012 11:07:08 +0100 Subject: [PATCH 2/3] added tests --- rest_framework/tests/models.py | 4 ++++ rest_framework/tests/serializer.py | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index cbdc765c8..f6e5333b1 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -154,3 +154,7 @@ class BlankFieldModel(RESTFrameworkModel): # Model for issue #380 class OptionalRelationModel(RESTFrameworkModel): other = models.ForeignKey('OptionalRelationModel', blank=True, null=True) + +# Model for RegexField +class Book(RESTFrameworkModel): + isbn = models.CharField(max_length=13) \ No newline at end of file diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 059593a90..ad100e539 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -2,7 +2,7 @@ import datetime from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, - BlankFieldModel, BlogPost, CallableDefaultValueModel, DefaultValueModel, + BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, ManyToManyModel, Person, ReadOnlyManyToManyModel) @@ -40,6 +40,13 @@ class CommentSerializer(serializers.Serializer): return instance +class BookSerializer(serializers.ModelSerializer): + isbn = serializers.RegexField(regex=r'^[0-9]{13}$', error_messages={'invalid': 'isbn has to be exact 13 numbers'}) + + class Meta: + model = Book + + class ActionItemSerializer(serializers.ModelSerializer): class Meta: model = ActionItem @@ -240,6 +247,25 @@ class ValidationTests(TestCase): self.assertEquals(serializer.errors, {}) +class RegexValidationTest(TestCase): + def test_create_failed(self): + serializer = BookSerializer(data={'isbn': '1234567890'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'isbn': [u'isbn has to be exact 13 numbers']}) + + serializer = BookSerializer(data={'isbn': '12345678901234'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'isbn': [u'isbn has to be exact 13 numbers']}) + + serializer = BookSerializer(data={'isbn': 'abcdefghijklm'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'isbn': [u'isbn has to be exact 13 numbers']}) + + def test_create_success(self): + serializer = BookSerializer(data={'isbn': '1234567890123'}) + self.assertTrue(serializer.is_valid()) + + class MetadataTests(TestCase): def test_empty(self): serializer = CommentSerializer() From 03100168ff96dd4a09ee7c8a5a63b294abe99dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Gro=C3=9F?= Date: Wed, 21 Nov 2012 11:57:00 +0100 Subject: [PATCH 3/3] added missing line --- rest_framework/tests/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 70523fc0d..c35861c6c 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -166,6 +166,7 @@ class BlankFieldModel(RESTFrameworkModel): class OptionalRelationModel(RESTFrameworkModel): other = models.ForeignKey('OptionalRelationModel', blank=True, null=True) + # Model for RegexField class Book(RESTFrameworkModel): isbn = models.CharField(max_length=13)