From 43fd5a873051c99600386c1fdc9fa368edeb6eda Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 29 Sep 2014 09:24:03 +0100 Subject: Uniqueness validation --- tests/test_validators.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/test_validators.py (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py new file mode 100644 index 00000000..a1366a1a --- /dev/null +++ b/tests/test_validators.py @@ -0,0 +1,35 @@ +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +class ExampleModel(models.Model): + username = models.CharField(unique=True, max_length=100) + + +class ExampleSerializer(serializers.ModelSerializer): + class Meta: + model = ExampleModel + + +class TestUniquenessValidation(TestCase): + def setUp(self): + self.instance = ExampleModel.objects.create(username='existing') + + def test_is_not_unique(self): + data = {'username': 'existing'} + serializer = ExampleSerializer(data=data) + assert not serializer.is_valid() + assert serializer.errors == {'username': ['This field must be unique.']} + + def test_is_unique(self): + data = {'username': 'other'} + serializer = ExampleSerializer(data=data) + assert serializer.is_valid() + assert serializer.validated_data == {'username': 'other'} + + def test_updated_instance_excluded(self): + data = {'username': 'existing'} + serializer = ExampleSerializer(self.instance, data=data) + assert serializer.is_valid() + assert serializer.validated_data == {'username': 'existing'} -- cgit v1.2.3 From 9805a085fb115785f272489dc24b51ba6f8e6329 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 29 Sep 2014 11:23:02 +0100 Subject: UniqueTogetherValidator --- tests/test_validators.py | 129 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 7 deletions(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index a1366a1a..c35ecb51 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -3,33 +3,148 @@ from django.test import TestCase from rest_framework import serializers -class ExampleModel(models.Model): +def dedent(blocktext): + return '\n'.join([line[12:] for line in blocktext.splitlines()[1:-1]]) + + +# Tests for `UniqueValidator` +# --------------------------- + +class UniquenessModel(models.Model): username = models.CharField(unique=True, max_length=100) -class ExampleSerializer(serializers.ModelSerializer): +class UniquenessSerializer(serializers.ModelSerializer): class Meta: - model = ExampleModel + model = UniquenessModel class TestUniquenessValidation(TestCase): def setUp(self): - self.instance = ExampleModel.objects.create(username='existing') + self.instance = UniquenessModel.objects.create(username='existing') + + def test_repr(self): + serializer = UniquenessSerializer() + expected = dedent(""" + UniquenessSerializer(): + id = IntegerField(label='ID', read_only=True) + username = CharField(max_length=100, validators=[]) + """) + assert repr(serializer) == expected def test_is_not_unique(self): data = {'username': 'existing'} - serializer = ExampleSerializer(data=data) + serializer = UniquenessSerializer(data=data) assert not serializer.is_valid() assert serializer.errors == {'username': ['This field must be unique.']} def test_is_unique(self): data = {'username': 'other'} - serializer = ExampleSerializer(data=data) + serializer = UniquenessSerializer(data=data) assert serializer.is_valid() assert serializer.validated_data == {'username': 'other'} def test_updated_instance_excluded(self): data = {'username': 'existing'} - serializer = ExampleSerializer(self.instance, data=data) + serializer = UniquenessSerializer(self.instance, data=data) assert serializer.is_valid() assert serializer.validated_data == {'username': 'existing'} + + +# Tests for `UniqueTogetherValidator` +# ----------------------------------- + +class UniquenessTogetherModel(models.Model): + race_name = models.CharField(max_length=100) + position = models.IntegerField() + + class Meta: + unique_together = ('race_name', 'position') + + +class UniquenessTogetherSerializer(serializers.ModelSerializer): + class Meta: + model = UniquenessTogetherModel + + +class TestUniquenessTogetherValidation(TestCase): + def setUp(self): + self.instance = UniquenessTogetherModel.objects.create( + race_name='example', + position=1 + ) + UniquenessTogetherModel.objects.create( + race_name='example', + position=2 + ) + UniquenessTogetherModel.objects.create( + race_name='other', + position=1 + ) + + def test_repr(self): + serializer = UniquenessTogetherSerializer() + expected = dedent(""" + UniquenessTogetherSerializer(validators=[]): + id = IntegerField(label='ID', read_only=True) + race_name = CharField(max_length=100) + position = IntegerField() + """) + assert repr(serializer) == expected + + def test_is_not_unique_together(self): + """ + Failing unique together validation should result in non field errors. + """ + data = {'race_name': 'example', 'position': 2} + serializer = UniquenessTogetherSerializer(data=data) + print serializer.validators + assert not serializer.is_valid() + assert serializer.errors == { + 'non_field_errors': [ + 'The fields race_name, position must make a unique set.' + ] + } + + def test_is_unique_together(self): + """ + In a unique together validation, one field may be non-unique + so long as the set as a whole is unique. + """ + data = {'race_name': 'other', 'position': 2} + serializer = UniquenessTogetherSerializer(data=data) + assert serializer.is_valid() + assert serializer.validated_data == { + 'race_name': 'other', + 'position': 2 + } + + def test_updated_instance_excluded_from_unique_together(self): + """ + When performing an update, the existing instance does not count + as a match against uniqueness. + """ + data = {'race_name': 'example', 'position': 1} + serializer = UniquenessTogetherSerializer(self.instance, data=data) + assert serializer.is_valid() + assert serializer.validated_data == { + 'race_name': 'example', + 'position': 1 + } + + def test_ignore_exlcuded_fields(self): + """ + When model fields are not included in a serializer, then uniqueness + validtors should not be added for that field. + """ + class ExcludedFieldSerializer(serializers.ModelSerializer): + class Meta: + model = UniquenessTogetherModel + fields = ('id', 'race_name',) + serializer = ExcludedFieldSerializer() + expected = dedent(""" + ExcludedFieldSerializer(): + id = IntegerField(label='ID', read_only=True) + race_name = CharField(max_length=100) + """) + assert repr(serializer) == expected -- cgit v1.2.3 From 4798df52df5d59cc570043e3eb7e26f7ce57b54f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 29 Sep 2014 12:57:05 +0100 Subject: Update release notes --- tests/test_validators.py | 1 - 1 file changed, 1 deletion(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index c35ecb51..ac04d2b4 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -98,7 +98,6 @@ class TestUniquenessTogetherValidation(TestCase): """ data = {'race_name': 'example', 'position': 2} serializer = UniquenessTogetherSerializer(data=data) - print serializer.validators assert not serializer.is_valid() assert serializer.errors == { 'non_field_errors': [ -- cgit v1.2.3 From 5f4cc52ef5c0f603420c6ea809594710a372d336 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 9 Oct 2014 10:11:44 +0100 Subject: Tweaking --- tests/test_validators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index ac04d2b4..1d081411 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -131,7 +131,7 @@ class TestUniquenessTogetherValidation(TestCase): 'position': 1 } - def test_ignore_exlcuded_fields(self): + def test_ignore_excluded_fields(self): """ When model fields are not included in a serializer, then uniqueness validtors should not be added for that field. -- cgit v1.2.3 From ae53fdff9c6bb3e81a1ec005134462f0d629688f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 22 Oct 2014 13:30:28 +0100 Subject: First pass at unique_for_date, unique_for_month, unique_for_year --- tests/test_validators.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index 1d081411..5adb7678 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -1,6 +1,7 @@ from django.db import models from django.test import TestCase from rest_framework import serializers +import datetime def dedent(blocktext): @@ -147,3 +148,70 @@ class TestUniquenessTogetherValidation(TestCase): race_name = CharField(max_length=100) """) assert repr(serializer) == expected + + +# Tests for `UniqueForDateValidator` +# ---------------------------------- + +class UniqueForDateModel(models.Model): + slug = models.CharField(max_length=100, unique_for_date='published') + published = models.DateField() + + +class UniqueForDateSerializer(serializers.ModelSerializer): + class Meta: + model = UniqueForDateModel + + +class TestUniquenessForDateValidation(TestCase): + def setUp(self): + self.instance = UniqueForDateModel.objects.create( + slug='existing', + published='2000-01-01' + ) + + def test_repr(self): + serializer = UniqueForDateSerializer() + expected = dedent(""" + UniqueForDateSerializer(validators=[]): + id = IntegerField(label='ID', read_only=True) + slug = CharField(max_length=100) + published = DateField() + """) + assert repr(serializer) == expected + + def test_is_not_unique_for_date(self): + """ + Failing unique for date validation should result in field error. + """ + data = {'slug': 'existing', 'published': '2000-01-01'} + serializer = UniqueForDateSerializer(data=data) + assert not serializer.is_valid() + assert serializer.errors == { + 'slug': ['This field must be unique for the "published" date.'] + } + + def test_is_unique_for_date(self): + """ + Passing unique for date validation. + """ + data = {'slug': 'existing', 'published': '2000-01-02'} + serializer = UniqueForDateSerializer(data=data) + assert serializer.is_valid() + assert serializer.validated_data == { + 'slug': 'existing', + 'published': datetime.date(2000, 1, 2) + } + + def test_updated_instance_excluded_from_unique_for_date(self): + """ + When performing an update, the existing instance does not count + as a match against unique_for_date. + """ + data = {'slug': 'existing', 'published': '2000-01-01'} + serializer = UniqueForDateSerializer(instance=self.instance, data=data) + assert serializer.is_valid() + assert serializer.validated_data == { + 'slug': 'existing', + 'published': datetime.date(2000, 1, 1) + } -- cgit v1.2.3 From 9ebaabd6eb31e18cf0bb1c70893f719f18ecb0f9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 28 Oct 2014 16:21:49 +0000 Subject: unique_for_date/unique_for_month/unique_for_year --- tests/test_validators.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index 5adb7678..6cc52c83 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -176,7 +176,7 @@ class TestUniquenessForDateValidation(TestCase): UniqueForDateSerializer(validators=[]): id = IntegerField(label='ID', read_only=True) slug = CharField(max_length=100) - published = DateField() + published = DateField(required=True) """) assert repr(serializer) == expected @@ -215,3 +215,40 @@ class TestUniquenessForDateValidation(TestCase): 'slug': 'existing', 'published': datetime.date(2000, 1, 1) } + + +class HiddenFieldUniqueForDateModel(models.Model): + slug = models.CharField(max_length=100, unique_for_date='published') + published = models.DateTimeField(auto_now_add=True) + + +class TestHiddenFieldUniquenessForDateValidation(TestCase): + def test_repr_date_field_not_included(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = HiddenFieldUniqueForDateModel + fields = ('id', 'slug') + + serializer = TestSerializer() + expected = dedent(""" + TestSerializer(validators=[]): + id = IntegerField(label='ID', read_only=True) + slug = CharField(max_length=100) + published = HiddenField(default=CreateOnlyDefault()) + """) + assert repr(serializer) == expected + + def test_repr_date_field_included(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = HiddenFieldUniqueForDateModel + fields = ('id', 'slug', 'published') + + serializer = TestSerializer() + expected = dedent(""" + TestSerializer(validators=[]): + id = IntegerField(label='ID', read_only=True) + slug = CharField(max_length=100) + published = DateTimeField(default=CreateOnlyDefault(), read_only=True) + """) + assert repr(serializer) == expected -- cgit v1.2.3 From 207208fedff2457e921ef7d825ea7c3933b5dd6e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 31 Oct 2014 16:38:39 +0000 Subject: Lazy loading of fields and validators. Closes #1963. --- tests/test_validators.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index 6cc52c83..e6e0b23a 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -86,10 +86,12 @@ class TestUniquenessTogetherValidation(TestCase): def test_repr(self): serializer = UniquenessTogetherSerializer() expected = dedent(""" - UniquenessTogetherSerializer(validators=[]): + UniquenessTogetherSerializer(): id = IntegerField(label='ID', read_only=True) race_name = CharField(max_length=100) position = IntegerField() + class Meta: + validators = [] """) assert repr(serializer) == expected @@ -173,10 +175,12 @@ class TestUniquenessForDateValidation(TestCase): def test_repr(self): serializer = UniqueForDateSerializer() expected = dedent(""" - UniqueForDateSerializer(validators=[]): + UniqueForDateSerializer(): id = IntegerField(label='ID', read_only=True) slug = CharField(max_length=100) published = DateField(required=True) + class Meta: + validators = [] """) assert repr(serializer) == expected @@ -231,10 +235,12 @@ class TestHiddenFieldUniquenessForDateValidation(TestCase): serializer = TestSerializer() expected = dedent(""" - TestSerializer(validators=[]): + TestSerializer(): id = IntegerField(label='ID', read_only=True) slug = CharField(max_length=100) published = HiddenField(default=CreateOnlyDefault()) + class Meta: + validators = [] """) assert repr(serializer) == expected @@ -246,9 +252,11 @@ class TestHiddenFieldUniquenessForDateValidation(TestCase): serializer = TestSerializer() expected = dedent(""" - TestSerializer(validators=[]): + TestSerializer(): id = IntegerField(label='ID', read_only=True) slug = CharField(max_length=100) published = DateTimeField(default=CreateOnlyDefault(), read_only=True) + class Meta: + validators = [] """) assert repr(serializer) == expected -- cgit v1.2.3 From f387cd89da55ef88fcac504f5795ea9b591f3fba Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 10 Nov 2014 12:21:27 +0000 Subject: Uniqueness constraints imply a forced 'required=True'. Refs #1945 --- tests/test_validators.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index e6e0b23a..86614b10 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -134,6 +134,17 @@ class TestUniquenessTogetherValidation(TestCase): 'position': 1 } + def test_unique_together_is_required(self): + """ + In a unique together validation, all fields are required. + """ + data = {'position': 2} + serializer = UniquenessTogetherSerializer(data=data, partial=True) + assert not serializer.is_valid() + assert serializer.errors == { + 'race_name': ['This field is required.'] + } + def test_ignore_excluded_fields(self): """ When model fields are not included in a serializer, then uniqueness -- cgit v1.2.3 From 8586290df80ac8448d71cdb3326bc822c399cad1 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 19 Nov 2014 13:55:10 +0000 Subject: Apply defaults and requiredness to unique_together fields. Closes #2092. --- tests/test_validators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/test_validators.py') diff --git a/tests/test_validators.py b/tests/test_validators.py index 86614b10..1df0641c 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -88,8 +88,8 @@ class TestUniquenessTogetherValidation(TestCase): expected = dedent(""" UniquenessTogetherSerializer(): id = IntegerField(label='ID', read_only=True) - race_name = CharField(max_length=100) - position = IntegerField() + race_name = CharField(max_length=100, required=True) + position = IntegerField(required=True) class Meta: validators = [] """) -- cgit v1.2.3