From e224061189a6a5ea2c063f3820239eed6c3a88fb Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 9 Nov 2012 17:01:20 +0000 Subject: Support for `read_only_fields` on `ModelSerializer` classes --- rest_framework/tests/serializer.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 8d1de429..059593a9 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -51,6 +51,7 @@ class PersonSerializer(serializers.ModelSerializer): class Meta: model = Person fields = ('name', 'age', 'info') + read_only_fields = ('age',) class BasicTests(TestCase): @@ -107,7 +108,8 @@ class BasicTests(TestCase): self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!') def test_model_fields_as_expected(self): - """ Make sure that the fields returned are the same as defined + """ + Make sure that the fields returned are the same as defined in the Meta data """ serializer = PersonSerializer(self.person) @@ -115,12 +117,25 @@ class BasicTests(TestCase): set(['name', 'age', 'info'])) def test_field_with_dictionary(self): - """ Make sure that dictionaries from fields are left intact + """ + Make sure that dictionaries from fields are left intact """ serializer = PersonSerializer(self.person) expected = self.person_data self.assertEquals(serializer.data['info'], expected) + def test_read_only_fields(self): + """ + Attempting to update fields set as read_only should have no effect. + """ + + serializer = PersonSerializer(self.person, data={'name': 'dwight', 'age': 99}) + self.assertEquals(serializer.is_valid(), True) + instance = serializer.save() + self.assertEquals(serializer.errors, {}) + # Assert age is unchanged (35) + self.assertEquals(instance.age, self.person_data['age']) + class ValidationTests(TestCase): def setUp(self): -- cgit v1.2.3 From df689a7442ee41e3922229397e174785619e1124 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Sat, 10 Nov 2012 12:00:20 +0100 Subject: Reproduces #380 --- rest_framework/tests/hyperlinkedserializers.py | 33 ++++++++++++++++++++++++-- rest_framework/tests/models.py | 5 ++++ 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index f71e2e28..3a955ddf 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -2,7 +2,7 @@ from django.conf.urls.defaults import patterns, url from django.test import TestCase from django.test.client import RequestFactory from rest_framework import generics, status, serializers -from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo +from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel factory = RequestFactory() @@ -67,6 +67,11 @@ class AlbumDetail(generics.RetrieveAPIView): model = Album +class OptionalRelationDetail(generics.RetrieveAPIView): + model = OptionalRelationModel + model_serializer_class = serializers.HyperlinkedModelSerializer + + urlpatterns = patterns('', url(r'^basic/$', BasicList.as_view(), name='basicmodel-list'), url(r'^basic/(?P\d+)/$', BasicDetail.as_view(), name='basicmodel-detail'), @@ -76,7 +81,8 @@ urlpatterns = patterns('', url(r'^posts/(?P\d+)/$', BlogPostDetail.as_view(), name='blogpost-detail'), url(r'^comments/$', BlogPostCommentListCreate.as_view(), name='blogpostcomment-list'), url(r'^albums/(?P\w[\w-]*)/$', AlbumDetail.as_view(), name='album-detail'), - url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list') + url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list'), + url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'), ) @@ -211,3 +217,26 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(self.post.photo_set.count(), 1) self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') + + +class TestOptionalRelationHyperlinkedView(TestCase): + urls = 'rest_framework.tests.hyperlinkedserializers' + + def setUp(self): + """ + Create 1 OptionaRelationModel intances. + """ + OptionalRelationModel().save() + self.objects = OptionalRelationModel.objects + self.detail_view = OptionalRelationDetail.as_view() + + def test_get_detail_view(self): + """ + GET requests to RetrieveAPIView with optional relations should return None + for non existing relations. + """ + request = factory.get('/optionalrelationmodel-detail/1') + response = self.detail_view(request, pk=1).render() + self.assertEquals(response.status_code, status.HTTP_200_OK) + + diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index a2aba5be..cbdc765c 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -149,3 +149,8 @@ class Person(RESTFrameworkModel): # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): title = models.CharField(max_length=100, blank=True) + + +# Model for issue #380 +class OptionalRelationModel(RESTFrameworkModel): + other = models.ForeignKey('OptionalRelationModel', blank=True, null=True) -- cgit v1.2.3 From 2a2ce406bc9f2ff37bd789db55e373a6447d6069 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Sat, 10 Nov 2012 12:23:19 +0100 Subject: Fixes #380 --- rest_framework/tests/hyperlinkedserializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index 3a955ddf..5ab850af 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -224,11 +224,12 @@ class TestOptionalRelationHyperlinkedView(TestCase): def setUp(self): """ - Create 1 OptionaRelationModel intances. + Create 1 OptionalRelationModel intances. """ OptionalRelationModel().save() self.objects = OptionalRelationModel.objects self.detail_view = OptionalRelationDetail.as_view() + self.data = {"url": "http://testserver/optionalrelation/1/", "other": None} def test_get_detail_view(self): """ @@ -238,5 +239,4 @@ class TestOptionalRelationHyperlinkedView(TestCase): request = factory.get('/optionalrelationmodel-detail/1') response = self.detail_view(request, pk=1).render() self.assertEquals(response.status_code, status.HTTP_200_OK) - - + self.assertEquals(response.data, self.data) -- cgit v1.2.3 From 21468a186785e38d622dc0bbe63515f320f9e479 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 13 Nov 2012 11:47:32 +0000 Subject: Fix broken depth argument --- rest_framework/tests/pk_relations.py | 1 + 1 file changed, 1 insertion(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pk_relations.py b/rest_framework/tests/pk_relations.py index 44ae4040..3dcc76f9 100644 --- a/rest_framework/tests/pk_relations.py +++ b/rest_framework/tests/pk_relations.py @@ -136,6 +136,7 @@ class PrimaryKeyManyToManyTests(TestCase): ] self.assertEquals(serializer.data, expected) + class PrimaryKeyForeignKeyTests(TestCase): def setUp(self): target = ForeignKeyTarget(name='target-1') -- cgit v1.2.3 From cc55a7b64310cdd4b8b96e8270a48fd994ede90c Mon Sep 17 00:00:00 2001 From: Ludwig Kraatz Date: Tue, 13 Nov 2012 18:00:41 +0100 Subject: Returning a Location Header on Create when creating a Resource with HyperlinkedIdentityField of any name --- rest_framework/tests/hyperlinkedserializers.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index 5ab850af..cc5a19c1 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -8,6 +8,7 @@ factory = RequestFactory() class BlogPostCommentSerializer(serializers.ModelSerializer): + custom_identity_field = serializers.HyperlinkedIdentityField(view_name='blogpostcomment-detail') text = serializers.CharField() blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail') @@ -17,6 +18,7 @@ class BlogPostCommentSerializer(serializers.ModelSerializer): class PhotoSerializer(serializers.Serializer): + """ When Adding a HyperlinkedIdentityField to this serializer, the TestCreateWithForeignKeysAndCustomSlug will fail """ description = serializers.CharField() album_url = serializers.HyperlinkedRelatedField(source='album', view_name='album-detail', queryset=Album.objects.all(), slug_field='title', slug_url_kwarg='title') @@ -53,6 +55,9 @@ class BlogPostCommentListCreate(generics.ListCreateAPIView): model = BlogPostComment serializer_class = BlogPostCommentSerializer +class BlogPostCommentDetail(generics.RetrieveAPIView): + model = BlogPostComment + serializer_class = BlogPostCommentSerializer class BlogPostDetail(generics.RetrieveAPIView): model = BlogPost @@ -80,6 +85,7 @@ urlpatterns = patterns('', url(r'^manytomany/(?P<pk>\d+)/$', ManyToManyDetail.as_view(), name='manytomanymodel-detail'), url(r'^posts/(?P<pk>\d+)/$', BlogPostDetail.as_view(), name='blogpost-detail'), url(r'^comments/$', BlogPostCommentListCreate.as_view(), name='blogpostcomment-list'), + url(r'^comments/(?P<pk>\d+)/$', BlogPostCommentDetail.as_view(), name='blogpostcomment-detail'), url(r'^albums/(?P<title>\w[\w-]*)/$', AlbumDetail.as_view(), name='album-detail'), url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list'), url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'), @@ -191,6 +197,7 @@ class TestCreateWithForeignKeys(TestCase): request = factory.post('/comments/', data=data) response = self.create_view(request).render() self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(response["Location"], 'http://testserver/comments/1/') self.assertEqual(self.post.blogpostcomment_set.count(), 1) self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment') @@ -215,6 +222,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): request = factory.post('/photos/', data=data) response = self.list_create_view(request).render() self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertNotIn("Location",response,msg="A Serializer without HyperlinkedIdentityField can not produce a valid Location header (for now). Thats why there shouldn'd be one") self.assertEqual(self.post.photo_set.count(), 1) self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') -- cgit v1.2.3 From 851dff1644f6dafd29838a997a788df51c0570a3 Mon Sep 17 00:00:00 2001 From: Ludwig Kraatz Date: Tue, 13 Nov 2012 18:39:07 +0100 Subject: fixed a bug on testing throttling headers after changing the headers storing of reponse --- rest_framework/tests/throttling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/throttling.py b/rest_framework/tests/throttling.py index 0b94c25b..4b98b941 100644 --- a/rest_framework/tests/throttling.py +++ b/rest_framework/tests/throttling.py @@ -106,7 +106,7 @@ class ThrottlingTests(TestCase): if expect is not None: self.assertEquals(response['X-Throttle-Wait-Seconds'], expect) else: - self.assertFalse('X-Throttle-Wait-Seconds' in response.headers) + self.assertFalse('X-Throttle-Wait-Seconds' in response) def test_seconds_fields(self): """ -- cgit v1.2.3 From b341dc70af828d066eb3891e8eafb6337cdd2d04 Mon Sep 17 00:00:00 2001 From: Ludwig Kraatz Date: Tue, 13 Nov 2012 19:15:42 +0100 Subject: fixed ugly code Location header is set just, if there is a Location field on the serializer. --- rest_framework/tests/hyperlinkedserializers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index cc5a19c1..5fc935ae 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -8,17 +8,16 @@ factory = RequestFactory() class BlogPostCommentSerializer(serializers.ModelSerializer): - custom_identity_field = serializers.HyperlinkedIdentityField(view_name='blogpostcomment-detail') + url = serializers.HyperlinkedIdentityField(view_name='blogpostcomment-detail') text = serializers.CharField() blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail') class Meta: model = BlogPostComment - fields = ('text', 'blog_post_url') + fields = ('text', 'blog_post_url', 'url') class PhotoSerializer(serializers.Serializer): - """ When Adding a HyperlinkedIdentityField to this serializer, the TestCreateWithForeignKeysAndCustomSlug will fail """ description = serializers.CharField() album_url = serializers.HyperlinkedRelatedField(source='album', view_name='album-detail', queryset=Album.objects.all(), slug_field='title', slug_url_kwarg='title') @@ -222,7 +221,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): request = factory.post('/photos/', data=data) response = self.list_create_view(request).render() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertNotIn("Location",response,msg="A Serializer without HyperlinkedIdentityField can not produce a valid Location header (for now). Thats why there shouldn'd be one") + self.assertNotIn("Location", response, msg="Location should only be included if there is a 'url' field on the serializer") self.assertEqual(self.post.photo_set.count(), 1) self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') -- cgit v1.2.3 From 8b999c6bb500a045c6c32412009cbd3b1cd5a56b Mon Sep 17 00:00:00 2001 From: Ludwig Kraatz Date: Wed, 14 Nov 2012 11:46:16 +0100 Subject: polishing code and adding myself to auhtors file --- rest_framework/tests/hyperlinkedserializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index 5fc935ae..d7effce7 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -196,7 +196,7 @@ class TestCreateWithForeignKeys(TestCase): request = factory.post('/comments/', data=data) response = self.create_view(request).render() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response["Location"], 'http://testserver/comments/1/') + self.assertEqual(response['Location'], 'http://testserver/comments/1/') self.assertEqual(self.post.blogpostcomment_set.count(), 1) self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment') @@ -221,7 +221,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): request = factory.post('/photos/', data=data) response = self.list_create_view(request).render() self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertNotIn("Location", response, msg="Location should only be included if there is a 'url' field on the serializer") + self.assertNotIn('Location', response, msg='Location should only be included if there is a "url" field on the serializer') self.assertEqual(self.post.photo_set.count(), 1) self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') -- cgit v1.2.3 From bd92db3c672137fa68185dbc0f453f7cea7caff3 Mon Sep 17 00:00:00 2001 From: Rob Romano Date: Sat, 10 Nov 2012 16:17:50 -0800 Subject: Added authtoken login/logout urlpatterns and views --- rest_framework/tests/authentication.py | 46 +++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 8ab4c4e4..d1bc23d9 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, include from django.contrib.auth.models import User from django.test import Client, TestCase @@ -27,6 +27,7 @@ MockView.authentication_classes += (TokenAuthentication,) urlpatterns = patterns('', (r'^$', MockView.as_view()), + (r'^auth-token/', include('rest_framework.authtoken.urls')), ) @@ -152,3 +153,46 @@ class TokenAuthTests(TestCase): self.token.delete() token = Token.objects.create(user=self.user) self.assertTrue(bool(token.key)) + + def test_token_login_json(self): + """Ensure token login view using JSON POST works.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username, 'password': self.password}), 'application/json') + self.assertEqual(response.status_code, 201) + self.assertEqual(json.loads(response.content)['token'], self.key) + + def test_token_login_json_bad_creds(self): + """Ensure token login view using JSON POST fails if bad credentials are used.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') + self.assertEqual(response.status_code, 400) + + def test_token_login_json_missing_fields(self): + """Ensure token login view using JSON POST fails if missing fields.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + json.dumps({'username': self.username}), 'application/json') + self.assertEqual(response.status_code, 400) + + def test_token_login_form(self): + """Ensure token login view using form POST works.""" + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/login/', + {'username': self.username, 'password': self.password}) + self.assertEqual(response.status_code, 201) + self.assertEqual(json.loads(response.content)['token'], self.key) + + def test_token_logout(self): + """Ensure token logout view using JSON POST works.""" + # Use different User and Token as to isolate this test's effects on other unittests in class + username = "ringo" + user = User.objects.create_user(username, "starr@thebeatles.com", "pass") + token = Token.objects.create(user=user) + auth = "Token " + token.key + client = Client(enforce_csrf_checks=True) + response = client.post('/auth-token/logout/', HTTP_AUTHORIZATION=auth) + self.assertEqual(response.status_code, 200) + # Ensure token no longer exists + self.assertRaises(Token.DoesNotExist, lambda token: Token.objects.get(key=token.key), token) -- cgit v1.2.3 From ce3ccb91dc2a7aaf8ff41ac24045c558d641839e Mon Sep 17 00:00:00 2001 From: Rob Romano Date: Mon, 12 Nov 2012 15:16:53 -0800 Subject: Updates to login view for TokenAuthentication from feedback from Tom --- rest_framework/tests/authentication.py | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index d1bc23d9..cb16ef1e 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -158,41 +158,28 @@ class TokenAuthTests(TestCase): """Ensure token login view using JSON POST works.""" client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', - json.dumps({'username': self.username, 'password': self.password}), 'application/json') - self.assertEqual(response.status_code, 201) + json.dumps({'username': self.username, 'password': self.password}), 'application/json') + self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content)['token'], self.key) def test_token_login_json_bad_creds(self): """Ensure token login view using JSON POST fails if bad credentials are used.""" client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', - json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') + json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') self.assertEqual(response.status_code, 400) def test_token_login_json_missing_fields(self): """Ensure token login view using JSON POST fails if missing fields.""" client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', - json.dumps({'username': self.username}), 'application/json') + json.dumps({'username': self.username}), 'application/json') self.assertEqual(response.status_code, 400) def test_token_login_form(self): """Ensure token login view using form POST works.""" client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', - {'username': self.username, 'password': self.password}) - self.assertEqual(response.status_code, 201) - self.assertEqual(json.loads(response.content)['token'], self.key) - - def test_token_logout(self): - """Ensure token logout view using JSON POST works.""" - # Use different User and Token as to isolate this test's effects on other unittests in class - username = "ringo" - user = User.objects.create_user(username, "starr@thebeatles.com", "pass") - token = Token.objects.create(user=user) - auth = "Token " + token.key - client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/logout/', HTTP_AUTHORIZATION=auth) + {'username': self.username, 'password': self.password}) self.assertEqual(response.status_code, 200) - # Ensure token no longer exists - self.assertRaises(Token.DoesNotExist, lambda token: Token.objects.get(key=token.key), token) + self.assertEqual(json.loads(response.content)['token'], self.key) -- cgit v1.2.3 From 321ba156ca45da8a4b3328c4aec6a9235f32e5f8 Mon Sep 17 00:00:00 2001 From: Rob Romano Date: Tue, 13 Nov 2012 16:49:13 -0800 Subject: Renamed AuthTokenView to ObtainAuthToken, added obtain_auth_token var, updated tests & docs. Left authtoken.urls in place as example. --- rest_framework/tests/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index cb16ef1e..96ca9f52 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -27,7 +27,7 @@ MockView.authentication_classes += (TokenAuthentication,) urlpatterns = patterns('', (r'^$', MockView.as_view()), - (r'^auth-token/', include('rest_framework.authtoken.urls')), + (r'^auth-token/', 'rest_framework.authtoken.views.obtain_auth_token'), ) -- cgit v1.2.3 From 69a01d71256b9923aac1b8d1b91063068ecfebf7 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Wed, 14 Nov 2012 23:04:46 +0100 Subject: Added a test for the FileField. --- rest_framework/tests/files.py | 55 +++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/files.py b/rest_framework/tests/files.py index 61d7f7b1..5dd57b7c 100644 --- a/rest_framework/tests/files.py +++ b/rest_framework/tests/files.py @@ -1,34 +1,39 @@ -# from django.test import TestCase -# from django import forms +import StringIO +import datetime -# from django.test.client import RequestFactory -# from rest_framework.views import View -# from rest_framework.response import Response +from django.test import TestCase -# import StringIO +from rest_framework import serializers -# class UploadFilesTests(TestCase): -# """Check uploading of files""" -# def setUp(self): -# self.factory = RequestFactory() +class UploadedFile(object): + def __init__(self, file, created=None): + self.file = file + self.created = created or datetime.datetime.now() -# def test_upload_file(self): -# class FileForm(forms.Form): -# file = forms.FileField() +class UploadedFileSerializer(serializers.Serializer): + file = serializers.FileField() + created = serializers.DateTimeField() -# class MockView(View): -# permissions = () -# form = FileForm + def restore_object(self, attrs, instance=None): + if instance: + instance.file = attrs['file'] + instance.created = attrs['created'] + return instance + return UploadedFile(**attrs) -# def post(self, request, *args, **kwargs): -# return Response({'FILE_NAME': self.CONTENT['file'].name, -# 'FILE_CONTENT': self.CONTENT['file'].read()}) -# file = StringIO.StringIO('stuff') -# file.name = 'stuff.txt' -# request = self.factory.post('/', {'file': file}) -# view = MockView.as_view() -# response = view(request) -# self.assertEquals(response.raw_content, {"FILE_CONTENT": "stuff", "FILE_NAME": "stuff.txt"}) +class FileSerializerTests(TestCase): + + def test_create(self): + now = datetime.datetime.now() + file = StringIO.StringIO('stuff') + file.name = 'stuff.txt' + file.size = file.len + serializer = UploadedFileSerializer(data={'created': now}, files={'file': file}) + uploaded_file = UploadedFile(file=file, created=now) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.object.created, uploaded_file.created) + self.assertEquals(serializer.object.file, uploaded_file.file) + self.assertFalse(serializer.object is uploaded_file) -- cgit v1.2.3 From a701a21587a69ed959533cbcfdaa9c63337c3ccc Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Thu, 15 Nov 2012 14:35:34 +0100 Subject: added page_size_kwarg tests --- rest_framework/tests/pagination.py | 143 ++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 713a7255..8aae2147 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -34,6 +34,29 @@ if django_filters: filter_backend = filters.DjangoFilterBackend +class DefaultPageSizeKwargView(generics.ListAPIView): + """ + View for testing default page_size usage + """ + model = BasicModel + + +class CustomPageSizeKwargView(generics.ListAPIView): + """ + View for testing custom page_size usage + """ + model = BasicModel + page_size_kwarg = 'ps' + + +class NonePageSizeKwargView(generics.ListAPIView): + """ + View for testing None page_size usage + """ + model = BasicModel + page_size_kwarg = None + + class IntegrationTestPagination(TestCase): """ Integration tests for paginated list views. @@ -135,7 +158,7 @@ class IntegrationTestPaginationAndFiltering(TestCase): class UnitTestPagination(TestCase): """ - Unit tests for pagination of primative objects. + Unit tests for pagination of primitive objects. """ def setUp(self): @@ -156,3 +179,121 @@ class UnitTestPagination(TestCase): self.assertEquals(serializer.data['next'], None) self.assertEquals(serializer.data['previous'], '?page=2') self.assertEquals(serializer.data['results'], self.objects[20:]) + + +class TestDefaultPageSizeKwarg(TestCase): + """ + Tests for list views with default page size kwarg + """ + + def setUp(self): + """ + Create 13 BasicModel instances. + """ + for i in range(13): + BasicModel(text=i).save() + self.objects = BasicModel.objects + self.data = [ + {'id': obj.id, 'text': obj.text} + for obj in self.objects.all() + ] + self.view = DefaultPageSizeKwargView.as_view() + + def test_default_page_size(self): + """ + Tests the default page size for this view. + no page size --> no limit --> no meta data + """ + request = factory.get('/') + response = self.view(request).render() + self.assertEquals(response.data, self.data) + + def test_default_page_size_kwarg(self): + """ + If page_size_kwarg is set not set, the default page_size kwarg should limit per view requests. + """ + request = factory.get('/?page_size=5') + response = self.view(request).render() + self.assertEquals(response.data['count'], 13) + self.assertEquals(response.data['results'], self.data[:5]) + + +class TestCustomPageSizeKwarg(TestCase): + """ + Tests for list views with default page size kwarg + """ + + def setUp(self): + """ + Create 13 BasicModel instances. + """ + for i in range(13): + BasicModel(text=i).save() + self.objects = BasicModel.objects + self.data = [ + {'id': obj.id, 'text': obj.text} + for obj in self.objects.all() + ] + self.view = CustomPageSizeKwargView.as_view() + + def test_default_page_size(self): + """ + Tests the default page size for this view. + no page size --> no limit --> no meta data + """ + request = factory.get('/') + response = self.view(request).render() + self.assertEquals(response.data, self.data) + + def test_disabled_default_page_size_kwarg(self): + """ + If page_size_kwarg is set set, the default page_size kwarg should not work. + """ + request = factory.get('/?page_size=5') + response = self.view(request).render() + self.assertEquals(response.data, self.data) + + def test_custom_page_size_kwarg(self): + """ + If page_size_kwarg is set set, the new kwarg should limit per view requests. + """ + request = factory.get('/?ps=5') + response = self.view(request).render() + self.assertEquals(response.data['count'], 13) + self.assertEquals(response.data['results'], self.data[:5]) + + +class TestNonePageSizeKwarg(TestCase): + """ + Tests for list views with default page size kwarg + """ + + def setUp(self): + """ + Create 13 BasicModel instances. + """ + for i in range(13): + BasicModel(text=i).save() + self.objects = BasicModel.objects + self.data = [ + {'id': obj.id, 'text': obj.text} + for obj in self.objects.all() + ] + self.view = NonePageSizeKwargView.as_view() + + def test_default_page_size(self): + """ + Tests the default page size for this view. + no page size --> no limit --> no meta data + """ + request = factory.get('/') + response = self.view(request).render() + self.assertEquals(response.data, self.data) + + def test_none_page_size_kwarg(self): + """ + If page_size_kwarg is set to None, custom page_size per request should be disabled. + """ + request = factory.get('/?page_size=5') + response = self.view(request).render() + self.assertEquals(response.data, self.data) -- cgit v1.2.3 From 4edc801d5912b2c31855647b432e461e35322511 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Fri, 16 Nov 2012 21:42:04 +0100 Subject: Reproduces #421 --- rest_framework/tests/serializer.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 059593a9..a51df146 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -239,6 +239,14 @@ class ValidationTests(TestCase): self.assertEquals(serializer.is_valid(), True) self.assertEquals(serializer.errors, {}) + def test_modelserializer_max_length_exceeded(self): + data = { + 'title': 'x' * 201, + } + serializer = ActionItemSerializer(data=data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 200 characters (it has 201).']}) + class MetadataTests(TestCase): def test_empty(self): -- cgit v1.2.3 From 1a436dd6d9f56b62de61c55c89084d60c09966ba Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Fri, 16 Nov 2012 22:43:16 +0100 Subject: Added URLField and SlugField. Fixed test_modelserializer_max_length_exceeded --- rest_framework/tests/serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index a51df146..fb1be7eb 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -245,7 +245,7 @@ class ValidationTests(TestCase): } serializer = ActionItemSerializer(data=data) self.assertEquals(serializer.is_valid(), False) - self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 200 characters (it has 201).']}) + self.assertEquals(serializer.errors, {'title': [u'Ensure this value has at most 200 characters (it has 201).']}) class MetadataTests(TestCase): -- cgit v1.2.3 From 31f01bd6315f46bf28bb4c9c25a5298785fc4fc6 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 16 Nov 2012 22:45:57 +0000 Subject: Polishing to page size query parameters & more docs --- rest_framework/tests/pagination.py | 85 ++++++-------------------------------- 1 file changed, 12 insertions(+), 73 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 8aae2147..3062007d 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -36,25 +36,17 @@ if django_filters: class DefaultPageSizeKwargView(generics.ListAPIView): """ - View for testing default page_size usage + View for testing default paginate_by_param usage """ model = BasicModel -class CustomPageSizeKwargView(generics.ListAPIView): +class PaginateByParamView(generics.ListAPIView): """ - View for testing custom page_size usage + View for testing custom paginate_by_param usage """ model = BasicModel - page_size_kwarg = 'ps' - - -class NonePageSizeKwargView(generics.ListAPIView): - """ - View for testing None page_size usage - """ - model = BasicModel - page_size_kwarg = None + paginate_by_param = 'page_size' class IntegrationTestPagination(TestCase): @@ -181,9 +173,9 @@ class UnitTestPagination(TestCase): self.assertEquals(serializer.data['results'], self.objects[20:]) -class TestDefaultPageSizeKwarg(TestCase): +class TestUnpaginated(TestCase): """ - Tests for list views with default page size kwarg + Tests for list views without pagination. """ def setUp(self): @@ -199,26 +191,17 @@ class TestDefaultPageSizeKwarg(TestCase): ] self.view = DefaultPageSizeKwargView.as_view() - def test_default_page_size(self): + def test_unpaginated(self): """ Tests the default page size for this view. no page size --> no limit --> no meta data """ request = factory.get('/') - response = self.view(request).render() + response = self.view(request) self.assertEquals(response.data, self.data) - def test_default_page_size_kwarg(self): - """ - If page_size_kwarg is set not set, the default page_size kwarg should limit per view requests. - """ - request = factory.get('/?page_size=5') - response = self.view(request).render() - self.assertEquals(response.data['count'], 13) - self.assertEquals(response.data['results'], self.data[:5]) - -class TestCustomPageSizeKwarg(TestCase): +class TestCustomPaginateByParam(TestCase): """ Tests for list views with default page size kwarg """ @@ -234,7 +217,7 @@ class TestCustomPageSizeKwarg(TestCase): {'id': obj.id, 'text': obj.text} for obj in self.objects.all() ] - self.view = CustomPageSizeKwargView.as_view() + self.view = PaginateByParamView.as_view() def test_default_page_size(self): """ @@ -245,55 +228,11 @@ class TestCustomPageSizeKwarg(TestCase): response = self.view(request).render() self.assertEquals(response.data, self.data) - def test_disabled_default_page_size_kwarg(self): + def test_paginate_by_param(self): """ - If page_size_kwarg is set set, the default page_size kwarg should not work. + If paginate_by_param is set, the new kwarg should limit per view requests. """ request = factory.get('/?page_size=5') response = self.view(request).render() - self.assertEquals(response.data, self.data) - - def test_custom_page_size_kwarg(self): - """ - If page_size_kwarg is set set, the new kwarg should limit per view requests. - """ - request = factory.get('/?ps=5') - response = self.view(request).render() self.assertEquals(response.data['count'], 13) self.assertEquals(response.data['results'], self.data[:5]) - - -class TestNonePageSizeKwarg(TestCase): - """ - Tests for list views with default page size kwarg - """ - - def setUp(self): - """ - Create 13 BasicModel instances. - """ - for i in range(13): - BasicModel(text=i).save() - self.objects = BasicModel.objects - self.data = [ - {'id': obj.id, 'text': obj.text} - for obj in self.objects.all() - ] - self.view = NonePageSizeKwargView.as_view() - - def test_default_page_size(self): - """ - Tests the default page size for this view. - no page size --> no limit --> no meta data - """ - request = factory.get('/') - response = self.view(request).render() - self.assertEquals(response.data, self.data) - - def test_none_page_size_kwarg(self): - """ - If page_size_kwarg is set to None, custom page_size per request should be disabled. - """ - request = factory.get('/?page_size=5') - response = self.view(request).render() - self.assertEquals(response.data, self.data) -- cgit v1.2.3 From d67ee708e5d9f28f26377df391f5e72708e073d2 Mon Sep 17 00:00:00 2001 From: Jacob Magnusson Date: Sun, 18 Nov 2012 18:14:21 +0100 Subject: Add support for min_length / max_length keywords on basic ModelFields --- rest_framework/tests/models.py | 8 ++++++++ rest_framework/tests/serializer.py | 10 ++++++++++ 2 files changed, 18 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index cbdc765c..59d81150 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -35,6 +35,13 @@ def foobar(): return 'foobar' +class CustomField(models.CharField): + + def __init__(self, *args, **kwargs): + kwargs['max_length'] = 12 + super(CustomField, self).__init__(*args, **kwargs) + + class RESTFrameworkModel(models.Model): """ Base for test models that sets app_label, so they play nicely. @@ -113,6 +120,7 @@ class Comment(RESTFrameworkModel): class ActionItem(RESTFrameworkModel): title = models.CharField(max_length=200) done = models.BooleanField(default=False) + info = CustomField(default='---', max_length=12) # Models for reverse relations diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index fb1be7eb..814c2499 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -41,6 +41,7 @@ class CommentSerializer(serializers.Serializer): class ActionItemSerializer(serializers.ModelSerializer): + class Meta: model = ActionItem @@ -247,6 +248,15 @@ class ValidationTests(TestCase): self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.errors, {'title': [u'Ensure this value has at most 200 characters (it has 201).']}) + def test_default_modelfield_max_length_exceeded(self): + data = { + 'title': 'Testing "info" field...', + 'info': 'x' * 13, + } + serializer = ActionItemSerializer(data=data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']}) + class MetadataTests(TestCase): def test_empty(self): -- cgit v1.2.3 From de5b071d677074ab3b6b33a843c4b05ba2052a6b Mon Sep 17 00:00:00 2001 From: Jamie Matthews Date: Mon, 19 Nov 2012 17:22:17 +0000 Subject: Add SerializerMethodField --- rest_framework/tests/serializer.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index fb1be7eb..cc6e9d5c 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -497,6 +497,40 @@ class ManyRelatedTests(TestCase): self.assertEqual(serializer.data, expected) +class SerializerMethodFieldTests(TestCase): + def setUp(self): + + class BoopSerializer(serializers.Serializer): + beep = serializers.SerializerMethodField('get_beep') + boop = serializers.Field() + boop_count = serializers.SerializerMethodField('get_boop_count') + + def get_beep(self, obj): + return 'hello!' + + def get_boop_count(self, obj): + return len(obj.boop) + + self.serializer_class = BoopSerializer + + def test_serializer_method_field(self): + + class MyModel(object): + boop = ['a', 'b', 'c'] + + source_data = MyModel() + + serializer = self.serializer_class(source_data) + + expected = { + 'beep': u'hello!', + 'boop': [u'a', u'b', u'c'], + 'boop_count': 3, + } + + self.assertEqual(serializer.data, expected) + + # Test for issue #324 class BlankFieldTests(TestCase): def setUp(self): -- cgit v1.2.3 From 68c397371c647e88270b8c9e9a6f5f610bbd3a2b Mon Sep 17 00:00:00 2001 From: Jamie Matthews Date: Tue, 20 Nov 2012 09:41:36 +0000 Subject: Fix related serializers with source argument that resolves to a callable --- rest_framework/tests/models.py | 3 +++ rest_framework/tests/serializer.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 59d81150..3704cda7 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -127,6 +127,9 @@ class ActionItem(RESTFrameworkModel): class BlogPost(RESTFrameworkModel): title = models.CharField(max_length=100) + def get_first_comment(self): + return self.blogpostcomment_set.all()[0] + class BlogPostComment(RESTFrameworkModel): text = models.TextField() diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 814c2499..9ca4f002 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -488,6 +488,7 @@ class ManyRelatedTests(TestCase): title = serializers.CharField() comments = BlogPostCommentSerializer(source='blogpostcomment_set') + self.comment_serializer_class = BlogPostCommentSerializer self.serializer_class = BlogPostSerializer def test_reverse_relations(self): @@ -506,6 +507,23 @@ class ManyRelatedTests(TestCase): self.assertEqual(serializer.data, expected) + def test_callable_source(self): + post = BlogPost.objects.create(title="Test blog post") + post.blogpostcomment_set.create(text="I love this blog post") + + class ExtendedBlogPostSerializer(self.serializer_class): + first_comment = self.comment_serializer_class(source='get_first_comment') + + serializer = ExtendedBlogPostSerializer(post) + expected = { + 'title': 'Test blog post', + 'comments': [ + {'text': 'I love this blog post'} + ], + 'first_comment': {'text': 'I love this blog post'} + } + self.assertEqual(serializer.data, expected) + # Test for issue #324 class BlankFieldTests(TestCase): -- cgit v1.2.3 From 3cc5349b2f98d9c70788a2aadefc150290316479 Mon Sep 17 00:00:00 2001 From: Jamie Matthews Date: Tue, 20 Nov 2012 09:49:54 +0000 Subject: Clean up and clarify tests for related serializers --- rest_framework/tests/serializer.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 9ca4f002..d522ef97 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -479,7 +479,10 @@ class CallableDefaultValueTests(TestCase): class ManyRelatedTests(TestCase): - def setUp(self): + def test_reverse_relations(self): + post = BlogPost.objects.create(title="Test blog post") + post.blogpostcomment_set.create(text="I hate this blog post") + post.blogpostcomment_set.create(text="I love this blog post") class BlogPostCommentSerializer(serializers.Serializer): text = serializers.CharField() @@ -488,15 +491,7 @@ class ManyRelatedTests(TestCase): title = serializers.CharField() comments = BlogPostCommentSerializer(source='blogpostcomment_set') - self.comment_serializer_class = BlogPostCommentSerializer - self.serializer_class = BlogPostSerializer - - def test_reverse_relations(self): - post = BlogPost.objects.create(title="Test blog post") - post.blogpostcomment_set.create(text="I hate this blog post") - post.blogpostcomment_set.create(text="I love this blog post") - - serializer = self.serializer_class(instance=post) + serializer = BlogPostSerializer(instance=post) expected = { 'title': 'Test blog post', 'comments': [ @@ -511,15 +506,17 @@ class ManyRelatedTests(TestCase): post = BlogPost.objects.create(title="Test blog post") post.blogpostcomment_set.create(text="I love this blog post") - class ExtendedBlogPostSerializer(self.serializer_class): - first_comment = self.comment_serializer_class(source='get_first_comment') + class BlogPostCommentSerializer(serializers.Serializer): + text = serializers.CharField() + + class BlogPostSerializer(serializers.Serializer): + title = serializers.CharField() + first_comment = BlogPostCommentSerializer(source='get_first_comment') + + serializer = BlogPostSerializer(post) - serializer = ExtendedBlogPostSerializer(post) expected = { 'title': 'Test blog post', - 'comments': [ - {'text': 'I love this blog post'} - ], 'first_comment': {'text': 'I love this blog post'} } self.assertEqual(serializer.data, expected) -- cgit v1.2.3 From c3644234cda5c457d72baf1fbf145f12f49a1fa4 Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Tue, 20 Nov 2012 11:01:21 -0800 Subject: Add support for partial serializer updates --- rest_framework/tests/serializer.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index d522ef97..882f769c 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -108,6 +108,18 @@ class BasicTests(TestCase): self.assertTrue(serializer.object is expected) self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!') + def test_partial_update(self): + msg = 'Merry New Year!' + partial_data = {'content': msg} + serializer = CommentSerializer(self.comment, data=partial_data) + self.assertEquals(serializer.is_valid(), False) + serializer = CommentSerializer(self.comment, data=partial_data, partial=True) + expected = self.comment + self.assertEqual(serializer.is_valid(), True) + self.assertEquals(serializer.object, expected) + self.assertTrue(serializer.object is expected) + self.assertEquals(serializer.data['content'], msg) + def test_model_fields_as_expected(self): """ Make sure that the fields returned are the same as defined -- cgit v1.2.3 From ed713d0354b67bdc64de9346b9a72e1adfced76e Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Wed, 21 Nov 2012 11:07:08 +0100 Subject: added tests --- rest_framework/tests/models.py | 4 ++++ rest_framework/tests/serializer.py | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index cbdc765c..f6e5333b 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 059593a9..ad100e53 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() -- cgit v1.2.3 From 03100168ff96dd4a09ee7c8a5a63b294abe99dfe Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Wed, 21 Nov 2012 11:57:00 +0100 Subject: added missing line --- rest_framework/tests/models.py | 1 + 1 file changed, 1 insertion(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 70523fc0..c35861c6 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) -- cgit v1.2.3 From ca5b99486d15e7392754178ab0948de2a60763a3 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Thu, 22 Nov 2012 22:36:37 +0100 Subject: Added _post_clean() behaviour by adding a .perform_model_validation() method. Fixed some tests that were failing due to extra strict validation. --- rest_framework/tests/models.py | 4 ++-- rest_framework/tests/serializer.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index c35861c6..9a59e841 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -61,7 +61,7 @@ class BasicModel(RESTFrameworkModel): class SlugBasedModel(RESTFrameworkModel): text = models.CharField(max_length=100) - slug = models.SlugField(max_length=32) + slug = models.SlugField(max_length=32, blank=True) class DefaultValueModel(RESTFrameworkModel): @@ -159,7 +159,7 @@ class Person(RESTFrameworkModel): # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): - title = models.CharField(max_length=100, blank=True) + title = models.CharField(max_length=100, blank=True, null=True) # Model for issue #380 diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 61a05da1..5751e894 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -169,7 +169,7 @@ class ValidationTests(TestCase): 'content': 'x' * 1001, 'created': datetime.datetime(2012, 1, 1) } - self.actionitem = ActionItem('Some to do item', + self.actionitem = ActionItem(title='Some to do item', ) def test_create(self): -- cgit v1.2.3 From 3f47f6cea9d178a57855e3b90208601b7e28a80f Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Thu, 22 Nov 2012 23:50:42 +0100 Subject: Added a validate_unique test. --- rest_framework/tests/serializer.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 5751e894..0baf0e89 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,7 +1,7 @@ import datetime from django.test import TestCase from rest_framework import serializers -from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, +from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, ManyToManyModel, Person, ReadOnlyManyToManyModel) @@ -48,7 +48,7 @@ class BookSerializer(serializers.ModelSerializer): class ActionItemSerializer(serializers.ModelSerializer): - + class Meta: model = ActionItem @@ -62,6 +62,12 @@ class PersonSerializer(serializers.ModelSerializer): read_only_fields = ('age',) +class AlbumsSerializer(serializers.ModelSerializer): + + class Meta: + model = Album + + class BasicTests(TestCase): def setUp(self): self.comment = Comment( @@ -276,6 +282,16 @@ class ValidationTests(TestCase): self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']}) + def test_validate_unique(self): + """ + Just check if serializers.ModelSerializer.perform_model_validation() handles unique checks via .full_clean() + """ + serializer = AlbumsSerializer(data={'title': 'a'}) + serializer.is_valid() + serializer.save() + second_serializer = AlbumsSerializer(data={'title': 'a'}) + self.assertFalse(second_serializer.is_valid()) + class RegexValidationTest(TestCase): def test_create_failed(self): -- cgit v1.2.3 From 85a921c7efcea50a5d594082f0e4ddeefd95402f Mon Sep 17 00:00:00 2001 From: Mark Hughes Date: Sat, 24 Nov 2012 17:18:32 +0000 Subject: Added setter to user property --- rest_framework/tests/request.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index ff48f3fa..2850992d 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -3,6 +3,8 @@ Tests for content parsing, and form-overloaded content parsing. """ from django.conf.urls.defaults import patterns from django.contrib.auth.models import User +from django.contrib.auth import authenticate, login, logout +from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, Client from django.utils import simplejson as json @@ -276,3 +278,29 @@ class TestContentParsingWithAuthentication(TestCase): # response = self.csrf_client.post('/', content) # self.assertEqual(status.OK, response.status_code, "POST data is malformed") + + +class TestUserSetter(TestCase): + + def setUp(self): + # Pass request object through session middleware so session is + # available to login and logout functions + self.request = Request(factory.get('/')) + SessionMiddleware().process_request(self.request) + + User.objects.create_user('ringo', 'starr@thebeatles.com', 'yellow') + self.user = authenticate(username='ringo', password='yellow') + + def test_user_can_be_set(self): + self.request.user = self.user + self.assertEqual(self.request.user, self.user) + + def test_user_can_login(self): + login(self.request, self.user) + self.assertEqual(self.request.user, self.user) + + def test_user_can_logout(self): + self.request.user = self.user + self.assertFalse(self.request.user.is_anonymous()) + logout(self.request) + self.assertTrue(self.request.user.is_anonymous()) -- cgit v1.2.3 From e7666014a85d65e204b40e1f54911e654f974932 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Mon, 26 Nov 2012 23:39:49 +0100 Subject: Added an assertion to the tests that checks the '.errors' value for the unique-test --- rest_framework/tests/serializer.py | 1 + 1 file changed, 1 insertion(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 0baf0e89..bdf72a91 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -291,6 +291,7 @@ class ValidationTests(TestCase): serializer.save() second_serializer = AlbumsSerializer(data={'title': 'a'}) self.assertFalse(second_serializer.is_valid()) + self.assertEqual(second_serializer.errors, {'title': [u'Album with this Title already exists.']}) class RegexValidationTest(TestCase): -- cgit v1.2.3 From 19f67bd578ecd15ab057c6aff8a9cc788a459d10 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Wed, 28 Nov 2012 23:05:33 +0200 Subject: also update test with response code 401 --- rest_framework/tests/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 96ca9f52..d12e6e2a 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -167,7 +167,7 @@ class TokenAuthTests(TestCase): client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') - self.assertEqual(response.status_code, 400) + self.assertEqual(response.status_code, 401) def test_token_login_json_missing_fields(self): """Ensure token login view using JSON POST fails if missing fields.""" -- cgit v1.2.3 From 1b9d0eefba07cb3567ad7dbeb72c4c3b3c1f0de3 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Thu, 29 Nov 2012 09:35:22 +0200 Subject: fix forgotten 400 test --- rest_framework/tests/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index d12e6e2a..802bc6c1 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -174,7 +174,7 @@ class TokenAuthTests(TestCase): client = Client(enforce_csrf_checks=True) response = client.post('/auth-token/login/', json.dumps({'username': self.username}), 'application/json') - self.assertEqual(response.status_code, 400) + self.assertEqual(response.status_code, 401) def test_token_login_form(self): """Ensure token login view using form POST works.""" -- cgit v1.2.3 From e311b763e193b41c6a679ddbcf813702691145a0 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Fri, 30 Nov 2012 01:34:46 +0200 Subject: add traverse_related feature + tests (fixes issue#461) --- rest_framework/tests/models.py | 25 ++++++++++++----------- rest_framework/tests/serializer.py | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 12 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index c35861c6..76435df8 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -124,8 +124,21 @@ class ActionItem(RESTFrameworkModel): # Models for reverse relations +class Person(RESTFrameworkModel): + name = models.CharField(max_length=10) + age = models.IntegerField(null=True, blank=True) + + @property + def info(self): + return { + 'name': self.name, + 'age': self.age, + } + + class BlogPost(RESTFrameworkModel): title = models.CharField(max_length=100) + writer = models.ForeignKey(Person, null=True, blank=True) def get_first_comment(self): return self.blogpostcomment_set.all()[0] @@ -145,18 +158,6 @@ class Photo(RESTFrameworkModel): album = models.ForeignKey(Album) -class Person(RESTFrameworkModel): - name = models.CharField(max_length=10) - age = models.IntegerField(null=True, blank=True) - - @property - def info(self): - return { - 'name': self.name, - 'age': self.age, - } - - # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): title = models.CharField(max_length=100, blank=True) diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 61a05da1..b16f2772 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -560,6 +560,47 @@ class ManyRelatedTests(TestCase): self.assertEqual(serializer.data, expected) +class RelatedTraversalTest(TestCase): + def test_nested_traversal(self): + user = Person.objects.create(name="django") + post = BlogPost.objects.create(title="Test blog post", writer=user) + post.blogpostcomment_set.create(text="I love this blog post") + + from rest_framework.tests.models import BlogPostComment + + class PersonSerializer(serializers.ModelSerializer): + class Meta: + model = Person + fields = ("name", "age") + + class BlogPostCommentSerializer(serializers.ModelSerializer): + class Meta: + model = BlogPostComment + fields = ("text", "post_owner") + + text = serializers.CharField() + post_owner = PersonSerializer(source='blog_post.writer') + + class BlogPostSerializer(serializers.Serializer): + title = serializers.CharField() + comments = BlogPostCommentSerializer(source='blogpostcomment_set') + + serializer = BlogPostSerializer(instance=post) + + expected = { + 'title': 'Test blog post', + 'comments': [{ + 'text': 'I hate this blog post', + 'post_owner': { + "name": "django", + "age": None + } + }] + } + + self.assertEqual(serializer.data, expected) + + class SerializerMethodFieldTests(TestCase): def setUp(self): -- cgit v1.2.3 From 1c1bd3fc5d7e65ae8c16e9946be87956c96a1723 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Fri, 30 Nov 2012 01:37:21 +0200 Subject: fix test response --- rest_framework/tests/serializer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index b16f2772..26a7d6bf 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -588,11 +588,11 @@ class RelatedTraversalTest(TestCase): serializer = BlogPostSerializer(instance=post) expected = { - 'title': 'Test blog post', + 'title': u'Test blog post', 'comments': [{ - 'text': 'I hate this blog post', + 'text': u'I love this blog post', 'post_owner': { - "name": "django", + "name": u"django", "age": None } }] -- cgit v1.2.3 From 705c7ad09db65c6ea6fb69bbd417cb7a45f6e3b9 Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Wed, 5 Dec 2012 17:43:47 -0700 Subject: added tests and fix for unpickleable metadata in SortedDictWithMetadata --- rest_framework/tests/serializer.py | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 61a05da1..af182917 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,9 +1,9 @@ -import datetime +import datetime, pickle from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel) + ManyToManyModel, Person, ReadOnlyManyToManyModel, BlogPostComment) class SubComment(object): @@ -641,3 +641,46 @@ class BlankFieldTests(TestCase): """ serializer = self.not_blank_model_serializer_class(data=self.data) self.assertEquals(serializer.is_valid(), False) + + +#class PersonGroup(object): +# name = "group" +# persons = [Person(name="joe"), Person(name="job")] +# +#class PersonGroupSerializer(serializers.Serializer): +# name = serializers.CharField() +# persons = PersonSerializer() +# +#class BlogPostSerializer(serializers.ModelSerializer): +# class Meta: +# model = BlogPost +# +# +#class BlogPostCommentSerializer(serializers.ModelSerializer): +# class Meta: +# model = BlogPostComment +# fields = ('text', 'blog_post') +# +# blog_post = BlogPostSerializer() +# + +#test for issue #460 +class SerializerPickleTests(TestCase): + """ Test pickleability of the output of Serializers + """ + def test_pickle_simple_model_serializer_data(self): + """ Test simple serializer + """ + pickle.dumps(PersonSerializer(Person(name="Methusela", age=969)).data) + + + def test_pickle_inner_serializer(self): + """ Test pickling a serializer whose resulting .data (a SortedDictWithMetadata) will + have unpickleable meta data--in order to make sure metadata doesn't get pulled into the pickle. + See DictWithMetadata.__getstate__ + """ + class InnerPersonSerializer(serializers.ModelSerializer): + class Meta: + model = Person + fields = ('name', 'age') + pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data) -- cgit v1.2.3 From 7f28a784146b9ba6ab303e79597f85a0f8b1e76e Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Wed, 5 Dec 2012 17:54:21 -0700 Subject: cleaned up last commit --- rest_framework/tests/serializer.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index af182917..9cedb54b 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -3,7 +3,7 @@ from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel, BlogPostComment) + ManyToManyModel, Person, ReadOnlyManyToManyModel) class SubComment(object): @@ -643,27 +643,6 @@ class BlankFieldTests(TestCase): self.assertEquals(serializer.is_valid(), False) -#class PersonGroup(object): -# name = "group" -# persons = [Person(name="joe"), Person(name="job")] -# -#class PersonGroupSerializer(serializers.Serializer): -# name = serializers.CharField() -# persons = PersonSerializer() -# -#class BlogPostSerializer(serializers.ModelSerializer): -# class Meta: -# model = BlogPost -# -# -#class BlogPostCommentSerializer(serializers.ModelSerializer): -# class Meta: -# model = BlogPostComment -# fields = ('text', 'blog_post') -# -# blog_post = BlogPostSerializer() -# - #test for issue #460 class SerializerPickleTests(TestCase): """ Test pickleability of the output of Serializers -- cgit v1.2.3 From cb7d9ea5c9843ffa99db4400670a11c3651520cc Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Thu, 6 Dec 2012 12:45:50 -0700 Subject: cleaned up white space & docstring styling --- rest_framework/tests/serializer.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 9cedb54b..31dd3699 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -645,18 +645,20 @@ class BlankFieldTests(TestCase): #test for issue #460 class SerializerPickleTests(TestCase): - """ Test pickleability of the output of Serializers + """ + Test pickleability of the output of Serializers """ def test_pickle_simple_model_serializer_data(self): - """ Test simple serializer + """ + Test simple serializer """ pickle.dumps(PersonSerializer(Person(name="Methusela", age=969)).data) - def test_pickle_inner_serializer(self): - """ Test pickling a serializer whose resulting .data (a SortedDictWithMetadata) will - have unpickleable meta data--in order to make sure metadata doesn't get pulled into the pickle. - See DictWithMetadata.__getstate__ + """ + Test pickling a serializer whose resulting .data (a SortedDictWithMetadata) will + have unpickleable meta data--in order to make sure metadata doesn't get pulled into the pickle. + See DictWithMetadata.__getstate__ """ class InnerPersonSerializer(serializers.ModelSerializer): class Meta: -- cgit v1.2.3 From 303bc7cf95033d2560668bf6f4d97f05f1268967 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 7 Dec 2012 21:32:39 +0000 Subject: Support nullable FKs, with blank=True --- rest_framework/tests/hyperlinkedserializers.py | 25 +++++++++--- rest_framework/tests/pk_relations.py | 53 ++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 9 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index d7effce7..24bf61bf 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -1,6 +1,7 @@ from django.conf.urls.defaults import patterns, url from django.test import TestCase from django.test.client import RequestFactory +from django.utils import simplejson as json from rest_framework import generics, status, serializers from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel @@ -54,10 +55,12 @@ class BlogPostCommentListCreate(generics.ListCreateAPIView): model = BlogPostComment serializer_class = BlogPostCommentSerializer + class BlogPostCommentDetail(generics.RetrieveAPIView): model = BlogPostComment serializer_class = BlogPostCommentSerializer + class BlogPostDetail(generics.RetrieveAPIView): model = BlogPost @@ -71,7 +74,7 @@ class AlbumDetail(generics.RetrieveAPIView): model = Album -class OptionalRelationDetail(generics.RetrieveAPIView): +class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView): model = OptionalRelationModel model_serializer_class = serializers.HyperlinkedModelSerializer @@ -162,7 +165,7 @@ class TestManyToManyHyperlinkedView(TestCase): GET requests to ListCreateAPIView should return list of objects. """ request = factory.get('/manytomany/') - response = self.list_view(request).render() + response = self.list_view(request) self.assertEquals(response.status_code, status.HTTP_200_OK) self.assertEquals(response.data, self.data) @@ -171,7 +174,7 @@ class TestManyToManyHyperlinkedView(TestCase): GET requests to ListCreateAPIView should return list of objects. """ request = factory.get('/manytomany/1/') - response = self.detail_view(request, pk=1).render() + response = self.detail_view(request, pk=1) self.assertEquals(response.status_code, status.HTTP_200_OK) self.assertEquals(response.data, self.data[0]) @@ -194,7 +197,7 @@ class TestCreateWithForeignKeys(TestCase): } request = factory.post('/comments/', data=data) - response = self.create_view(request).render() + response = self.create_view(request) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response['Location'], 'http://testserver/comments/1/') self.assertEqual(self.post.blogpostcomment_set.count(), 1) @@ -219,7 +222,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): } request = factory.post('/photos/', data=data) - response = self.list_create_view(request).render() + response = self.list_create_view(request) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertNotIn('Location', response, msg='Location should only be included if there is a "url" field on the serializer') self.assertEqual(self.post.photo_set.count(), 1) @@ -244,6 +247,16 @@ class TestOptionalRelationHyperlinkedView(TestCase): for non existing relations. """ request = factory.get('/optionalrelationmodel-detail/1') - response = self.detail_view(request, pk=1).render() + response = self.detail_view(request, pk=1) self.assertEquals(response.status_code, status.HTTP_200_OK) self.assertEquals(response.data, self.data) + + def test_put_detail_view(self): + """ + PUT requests to RetrieveUpdateDestroyAPIView with optional relations + should accept None for non existing relations. + """ + response = self.client.put('/optionalrelation/1/', + data=json.dumps(self.data), + content_type='application/json') + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/rest_framework/tests/pk_relations.py b/rest_framework/tests/pk_relations.py index 3dcc76f9..53245d94 100644 --- a/rest_framework/tests/pk_relations.py +++ b/rest_framework/tests/pk_relations.py @@ -49,9 +49,22 @@ class ForeignKeySourceSerializer(serializers.ModelSerializer): model = ForeignKeySource +# Nullable ForeignKey + +class NullableForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') + + +class NullableForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + model = NullableForeignKeySource + + # TODO: Add test that .data cannot be accessed prior to .is_valid -class PrimaryKeyManyToManyTests(TestCase): +class PKManyToManyTests(TestCase): def setUp(self): for idx in range(1, 4): target = ManyToManyTarget(name='target-%d' % idx) @@ -137,7 +150,7 @@ class PrimaryKeyManyToManyTests(TestCase): self.assertEquals(serializer.data, expected) -class PrimaryKeyForeignKeyTests(TestCase): +class PKForeignKeyTests(TestCase): def setUp(self): target = ForeignKeyTarget(name='target-1') target.save() @@ -174,7 +187,7 @@ class PrimaryKeyForeignKeyTests(TestCase): self.assertEquals(serializer.data, data) serializer.save() - # # Ensure source 1 is updated, and everything else is as expected + # Ensure source 1 is updated, and everything else is as expected queryset = ForeignKeySource.objects.all() serializer = ForeignKeySourceSerializer(queryset) expected = [ @@ -184,6 +197,40 @@ class PrimaryKeyForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_foreign_key_update_with_invalid_null(self): + data = {'id': 1, 'name': u'source-1', 'target': None} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) + + +class PKNullableForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + for idx in range(1, 4): + source = NullableForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_update_with_valid_null(self): + data = {'id': 1, 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': None}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + # reverse foreign keys MUST be read_only # In the general case they do not provide .remove() or .clear() # and cannot be arbitrarily set. -- cgit v1.2.3 From c911d54ae3769243fe6c74c29b5d16c7ac6efa10 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 7 Dec 2012 22:25:16 +0000 Subject: Reverted #458 When incorrect parameters are supplied to the obtain auth token view 400 *is* the correct response. --- rest_framework/tests/authentication.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 802bc6c1..d498ae3e 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, include +from django.conf.urls.defaults import patterns from django.contrib.auth.models import User from django.test import Client, TestCase @@ -27,7 +27,7 @@ MockView.authentication_classes += (TokenAuthentication,) urlpatterns = patterns('', (r'^$', MockView.as_view()), - (r'^auth-token/', 'rest_framework.authtoken.views.obtain_auth_token'), + (r'^auth-token/$', 'rest_framework.authtoken.views.obtain_auth_token'), ) @@ -157,7 +157,7 @@ class TokenAuthTests(TestCase): def test_token_login_json(self): """Ensure token login view using JSON POST works.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/', json.dumps({'username': self.username, 'password': self.password}), 'application/json') self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content)['token'], self.key) @@ -165,21 +165,21 @@ class TokenAuthTests(TestCase): def test_token_login_json_bad_creds(self): """Ensure token login view using JSON POST fails if bad credentials are used.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/', json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') - self.assertEqual(response.status_code, 401) + self.assertEqual(response.status_code, 400) def test_token_login_json_missing_fields(self): """Ensure token login view using JSON POST fails if missing fields.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/', json.dumps({'username': self.username}), 'application/json') - self.assertEqual(response.status_code, 401) + self.assertEqual(response.status_code, 400) def test_token_login_form(self): """Ensure token login view using form POST works.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/', {'username': self.username, 'password': self.password}) self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content)['token'], self.key) -- cgit v1.2.3 From f72be7b8faf4489c904bb6df97d51274872315bb Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 8 Dec 2012 12:29:35 +0000 Subject: Add test for m2m create --- rest_framework/tests/pk_relations.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pk_relations.py b/rest_framework/tests/pk_relations.py index 53245d94..3fb3a07b 100644 --- a/rest_framework/tests/pk_relations.py +++ b/rest_framework/tests/pk_relations.py @@ -130,6 +130,25 @@ class PKManyToManyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_many_to_many_create(self): + data = {'id': 4, 'name': u'source-4', 'targets': [1, 3]} + serializer = ManyToManySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is added, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'targets': [1]}, + {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, + {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]}, + {'id': 4, 'name': u'source-4', 'targets': [1, 3]}, + ] + self.assertEquals(serializer.data, expected) + def test_reverse_many_to_many_create(self): data = {'id': 4, 'name': u'target-4', 'sources': [1, 3]} serializer = ManyToManyTargetSerializer(data=data) -- cgit v1.2.3 From 936fdfb78e6987ce18812fbe3e17e2af8822704e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 8 Dec 2012 12:48:27 +0000 Subject: More tests for nullable FKs --- rest_framework/tests/pk_relations.py | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pk_relations.py b/rest_framework/tests/pk_relations.py index 3fb3a07b..e3360939 100644 --- a/rest_framework/tests/pk_relations.py +++ b/rest_framework/tests/pk_relations.py @@ -232,6 +232,49 @@ class PKNullableForeignKeyTests(TestCase): source = NullableForeignKeySource(name='source-%d' % idx, target=target) source.save() + def test_foreign_key_create_with_valid_null(self): + data = {'id': 4, 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 4, 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_create_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'id': 4, 'name': u'source-4', 'target': ''} + expected_data = {'id': 4, 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, expected_data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 4, 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + def test_foreign_key_update_with_valid_null(self): data = {'id': 1, 'name': u'source-1', 'target': None} instance = NullableForeignKeySource.objects.get(pk=1) @@ -250,6 +293,29 @@ class PKNullableForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_foreign_key_update_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'id': 1, 'name': u'source-1', 'target': ''} + expected_data = {'id': 1, 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, expected_data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': None}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + # reverse foreign keys MUST be read_only # In the general case they do not provide .remove() or .clear() # and cannot be arbitrarily set. -- cgit v1.2.3 From d0935d1fbb87711b0ffda8655c44ede29ee4208a Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Mon, 10 Dec 2012 23:10:04 +0100 Subject: get_excluded_fieldnames() should respect Meta options' ability to be either a tuple or list. Fixes #490. Refactored `if self.opt.fields` out of the for loop. Updated and cleaned up the validation-tests. --- rest_framework/tests/serializer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 455fa270..a16f6abd 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -66,6 +66,7 @@ class AlbumsSerializer(serializers.ModelSerializer): class Meta: model = Album + fields = ['title'] # lists are also valid options class BasicTests(TestCase): @@ -282,9 +283,11 @@ class ValidationTests(TestCase): self.assertEquals(serializer.is_valid(), False) self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']}) + +class ModelValidationTests(TestCase): def test_validate_unique(self): """ - Just check if serializers.ModelSerializer.perform_model_validation() handles unique checks via .full_clean() + Just check if serializers.ModelSerializer handles unique checks via .full_clean() """ serializer = AlbumsSerializer(data={'title': 'a'}) serializer.is_valid() -- cgit v1.2.3 From 80f15c598afe138df4170ceb2198484889511d0c Mon Sep 17 00:00:00 2001 From: George Kappel Date: Tue, 11 Dec 2012 09:14:52 -0600 Subject: Added depth test --- rest_framework/tests/serializer.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index a16f6abd..f80762f0 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -726,3 +726,24 @@ class SerializerPickleTests(TestCase): model = Person fields = ('name', 'age') pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data) + +class DepthTest(TestCase): + def test_depth(self): + user = Person.objects.create(name="django",age=1) + post = BlogPost.objects.create(title="Test blog post", writer=user) + + class PersonSerializer(serializers.ModelSerializer): + class Meta: + model = Person + fields = ("name", "age") + + class BlogPostSerializer(serializers.ModelSerializer): + class Meta: + model = BlogPost + depth = 1 + + serializer = BlogPostSerializer(instance=post) + expected = {'id': 1, 'title': u'Test blog post', + 'writer': {'id': 1, 'name': u'django', 'age':1}} + + self.assertEqual(serializer.data, expected) -- cgit v1.2.3 From 405822330958c5432dde56b07a61b223c03ca4c7 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 11 Dec 2012 21:07:25 +0000 Subject: Fix broken nested fields --- rest_framework/tests/serializer.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index f80762f0..50a5f5a4 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,4 +1,5 @@ -import datetime, pickle +import datetime +import pickle from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel, @@ -727,23 +728,39 @@ class SerializerPickleTests(TestCase): fields = ('name', 'age') pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data) + class DepthTest(TestCase): - def test_depth(self): - user = Person.objects.create(name="django",age=1) - post = BlogPost.objects.create(title="Test blog post", writer=user) + def test_implicit_nesting(self): + writer = Person.objects.create(name="django", age=1) + post = BlogPost.objects.create(title="Test blog post", writer=writer) + + class BlogPostSerializer(serializers.ModelSerializer): + class Meta: + model = BlogPost + depth = 1 + + serializer = BlogPostSerializer(instance=post) + expected = {'id': 1, 'title': u'Test blog post', + 'writer': {'id': 1, 'name': u'django', 'age': 1}} + + self.assertEqual(serializer.data, expected) + + def test_explicit_nesting(self): + writer = Person.objects.create(name="django", age=1) + post = BlogPost.objects.create(title="Test blog post", writer=writer) class PersonSerializer(serializers.ModelSerializer): class Meta: model = Person - fields = ("name", "age") class BlogPostSerializer(serializers.ModelSerializer): + writer = PersonSerializer() + class Meta: model = BlogPost - depth = 1 serializer = BlogPostSerializer(instance=post) expected = {'id': 1, 'title': u'Test blog post', - 'writer': {'id': 1, 'name': u'django', 'age':1}} + 'writer': {'id': 1, 'name': u'django', 'age': 1}} self.assertEqual(serializer.data, expected) -- cgit v1.2.3 From 497da7fc699b9e88c966e37bc48739865336683d Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 12 Dec 2012 20:44:55 +0000 Subject: Clean up field initialization. Fixes #497 --- rest_framework/tests/serializer.py | 54 +++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 50a5f5a4..780177aa 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -4,7 +4,7 @@ from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel) + ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo) class SubComment(object): @@ -764,3 +764,55 @@ class DepthTest(TestCase): 'writer': {'id': 1, 'name': u'django', 'age': 1}} self.assertEqual(serializer.data, expected) + + +class NestedSerializerContextTests(TestCase): + + def test_nested_serializer_context(self): + """ + Regression for #497 + + https://github.com/tomchristie/django-rest-framework/issues/497 + """ + class PhotoSerializer(serializers.ModelSerializer): + class Meta: + model = Photo + fields = ("description", "callable") + + callable = serializers.SerializerMethodField('_callable') + + def _callable(self, instance): + if not 'context_item' in self.context: + raise RuntimeError("context isn't getting passed into 2nd level nested serializer") + return "success" + + class AlbumSerializer(serializers.ModelSerializer): + class Meta: + model = Album + fields = ("photo_set", "callable") + + photo_set = PhotoSerializer(source="photo_set") + callable = serializers.SerializerMethodField("_callable") + + def _callable(self, instance): + if not 'context_item' in self.context: + raise RuntimeError("context isn't getting passed into 1st level nested serializer") + return "success" + + class AlbumCollection(object): + albums = None + + class AlbumCollectionSerializer(serializers.Serializer): + albums = AlbumSerializer(source="albums") + + album1 = Album.objects.create(title="album 1") + album2 = Album.objects.create(title="album 2") + Photo.objects.create(description="Bigfoot", album=album1) + Photo.objects.create(description="Unicorn", album=album1) + Photo.objects.create(description="Yeti", album=album2) + Photo.objects.create(description="Sasquatch", album=album2) + album_collection = AlbumCollection() + album_collection.albums = [album1, album2] + + # This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers + AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data -- cgit v1.2.3 From 5f08ec70e24ee3bdf74eed62def2fd9108af0eb0 Mon Sep 17 00:00:00 2001 From: Szymon Teżewski Date: Thu, 13 Dec 2012 12:07:56 +0100 Subject: context to custom field in pagination --- rest_framework/tests/pagination.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 3062007d..9c34001d 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -4,7 +4,7 @@ from django.core.paginator import Paginator from django.test import TestCase from django.test.client import RequestFactory from django.utils import unittest -from rest_framework import generics, status, pagination, filters +from rest_framework import generics, status, pagination, filters, serializers from rest_framework.compat import django_filters from rest_framework.tests.models import BasicModel, FilterableItem @@ -236,3 +236,32 @@ class TestCustomPaginateByParam(TestCase): response = self.view(request).render() self.assertEquals(response.data['count'], 13) self.assertEquals(response.data['results'], self.data[:5]) + + +class CustomField(serializers.Field): + def to_native(self, value): + if not 'view' in self.context: + raise RuntimeError("context isn't getting passed into custom field") + return "value" + + +class BasicModelSerializer(serializers.Serializer): + text = CustomField() + + +class TestContextPassedToCustomField(TestCase): + def setUp(self): + BasicModel.objects.create(text='ala ma kota') + + def test_with_pagination(self): + class ListView(generics.ListCreateAPIView): + model = BasicModel + serializer_class = BasicModelSerializer + paginate_by = 1 + + self.view = ListView.as_view() + request = factory.get('/') + response = self.view(request).render() + + self.assertEquals(response.status_code, status.HTTP_200_OK) + -- cgit v1.2.3 From 9eaf8e4330e0c6a4485dba650481a2578a3979b4 Mon Sep 17 00:00:00 2001 From: Simon Pantzare Date: Thu, 13 Dec 2012 17:57:27 +0100 Subject: Test to verify that context is passed on The paginator and its object serializer should share the same context. --- rest_framework/tests/pagination.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 3062007d..7bc23f1d 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -4,7 +4,7 @@ from django.core.paginator import Paginator from django.test import TestCase from django.test.client import RequestFactory from django.utils import unittest -from rest_framework import generics, status, pagination, filters +from rest_framework import generics, status, pagination, filters, serializers from rest_framework.compat import django_filters from rest_framework.tests.models import BasicModel, FilterableItem @@ -148,6 +148,12 @@ class IntegrationTestPaginationAndFiltering(TestCase): self.assertEquals(response.data['previous'], None) +class PassOnContextPaginationSerializer(pagination.PaginationSerializer): + + class Meta: + object_serializer_class = serializers.Serializer + + class UnitTestPagination(TestCase): """ Unit tests for pagination of primitive objects. @@ -172,6 +178,12 @@ class UnitTestPagination(TestCase): self.assertEquals(serializer.data['previous'], '?page=2') self.assertEquals(serializer.data['results'], self.objects[20:]) + def test_context_available_in_result(self): + serializer = PassOnContextPaginationSerializer(self.first_page) + results = serializer.fields[serializer.results_field] + # assertIs is available in Python 2.7 + self.assertTrue(serializer.context is results.context) + class TestUnpaginated(TestCase): """ -- cgit v1.2.3 From 39b01d6802310a90487f217c3de5428144c93429 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 14 Dec 2012 19:59:21 +0000 Subject: Ensure context is passed to dynamically added fields. Fixes #476. --- rest_framework/tests/pagination.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 7bc23f1d..3c65e9db 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -149,7 +149,6 @@ class IntegrationTestPaginationAndFiltering(TestCase): class PassOnContextPaginationSerializer(pagination.PaginationSerializer): - class Meta: object_serializer_class = serializers.Serializer @@ -179,9 +178,12 @@ class UnitTestPagination(TestCase): self.assertEquals(serializer.data['results'], self.objects[20:]) def test_context_available_in_result(self): + """ + Ensure context gets passed through to the object serializer. + """ serializer = PassOnContextPaginationSerializer(self.first_page) + serializer.data results = serializer.fields[serializer.results_field] - # assertIs is available in Python 2.7 self.assertTrue(serializer.context is results.context) -- cgit v1.2.3 From 35f72cecb199e1790a42fadd6037da43cdd5a05a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 15 Dec 2012 20:40:41 +0000 Subject: Fix model validation exclusions. Fixes #500. Fixes #506. --- rest_framework/tests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 428bf130..e2b287d0 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -61,7 +61,7 @@ class BasicModel(RESTFrameworkModel): class SlugBasedModel(RESTFrameworkModel): text = models.CharField(max_length=100) - slug = models.SlugField(max_length=32, blank=True) + slug = models.SlugField(max_length=32) class DefaultValueModel(RESTFrameworkModel): -- cgit v1.2.3 From 01e06bcdf8a4678a312acbf11638fa6a033c50d6 Mon Sep 17 00:00:00 2001 From: Joel Marcotte Date: Sat, 15 Dec 2012 16:33:08 -0500 Subject: Added test for "positive_integer in choices tuple does not get parsed if not string". Signed-off-by: Joel Marcotte <skaner@gmail.com> --- rest_framework/tests/models.py | 4 ++++ rest_framework/tests/serializer.py | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 428bf130..807bcf98 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -51,6 +51,10 @@ class RESTFrameworkModel(models.Model): abstract = True +class HasPositiveIntegerAsChoice(RESTFrameworkModel): + some_choices = ((1,'A'),(2,'B'),(3,'C')) + some_integer = models.PositiveIntegerField(choices=some_choices) + class Anchor(RESTFrameworkModel): text = models.CharField(max_length=100, default='anchor') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 780177aa..7f2c27b0 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -2,7 +2,7 @@ import datetime import pickle from django.test import TestCase from rest_framework import serializers -from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel, +from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo) @@ -69,6 +69,11 @@ class AlbumsSerializer(serializers.ModelSerializer): model = Album fields = ['title'] # lists are also valid options +class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer): + class Meta: + model = HasPositiveIntegerAsChoice + fields = ['some_integer'] + class BasicTests(TestCase): def setUp(self): @@ -285,6 +290,12 @@ class ValidationTests(TestCase): self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']}) +class PositiveIntegerAsChoiceTests(TestCase): + def test_positive_integer_in_json_is_correctly_parsed(self): + data = {'some_integer':1} + serializer = PositiveIntegerAsChoiceSerializer(data=data) + self.assertEquals(serializer.is_valid(), True) + class ModelValidationTests(TestCase): def test_validate_unique(self): """ -- cgit v1.2.3 From 008dafce178181855d66981cfacb908d013c5d1d Mon Sep 17 00:00:00 2001 From: toran billups Date: Sat, 15 Dec 2012 20:55:36 -0600 Subject: ManyPrimaryKeyRelatedField now supports create for one-to-many rel --- rest_framework/tests/models.py | 5 +++ rest_framework/tests/serializer.py | 79 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 428bf130..0aa00d76 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -149,6 +149,11 @@ class BlogPostComment(RESTFrameworkModel): blog_post = models.ForeignKey(BlogPost) +class BlogPostRelatedComment(RESTFrameworkModel): + text = models.TextField() + blog_post = models.ForeignKey(BlogPost, related_name="comments") + + class Album(RESTFrameworkModel): title = models.CharField(max_length=100, unique=True) diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 780177aa..3c56f127 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -816,3 +816,82 @@ class NestedSerializerContextTests(TestCase): # This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data + + +class ManyPrimaryKeyRelatedCreateTest(TestCase): + + def test_create_is_valid_with_title_and_empty_comments_list(self): + data = {'title': 'foobar', 'comments': []} + serializer = self.build_model_serializer(data) + self.assertEquals(serializer.is_valid(), True) + + def test_create_is_valid_with_title_and_comment(self): + data = {'title': 'foobar', 'comments': [self.comment.pk]} + serializer = self.build_model_serializer(data) + self.assertEquals(serializer.is_valid(), True) + + def test_create_is_not_valid_when_title_is_empty_string(self): + data = {'title': '', 'comments': [self.comment.pk]} + serializer = self.build_model_serializer(data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'title': [u'This field is required.']}) + + def test_create_is_not_valid_when_title_present_but_no_comments(self): + data = {'title': 'foobar'} + serializer = self.build_model_serializer(data) + try: + self.assertEquals(serializer.is_valid(), False) + except TypeError as e: + self.assertEqual(e.message, "'NoneType' object is not iterable") + + def test_create_without_comment_returns_expected_json_result(self): + data = {'title': 'foobar', 'comments': []} + serializer = self.build_model_serializer(data) + self.assertEquals(serializer.is_valid(), True) + instance = serializer.save() + expected = { + 'title': u'foobar', + 'comments': [] + } + self.assertEqual(serializer.data, expected) + + def test_create_with_comment_returns_expected_json_result(self): + data = {'title': 'foobar', 'comments': [self.comment.pk]} + serializer = self.build_model_serializer(data) + self.assertEquals(serializer.is_valid(), True) + instance = serializer.save() + expected = { + 'title': u'foobar', + 'comments': [self.comment.pk] + } + self.assertEqual(serializer.data, expected) + + @property + def comment(self): + if not hasattr(self, '_comment'): + from rest_framework.tests.models import BlogPostRelatedComment + self._comment = BlogPostRelatedComment.objects.create(text="I love this blog post", blog_post=self.post) + return self._comment + + @property + def post(self): + if not hasattr(self, '_post'): + from rest_framework.tests.models import BlogPost + self._post = BlogPost.objects.create(title="Test blog post") + return self._post + + def build_model_serializer(self, data): + from rest_framework.tests.models import BlogPost, BlogPostRelatedComment + + class BlogPostRelatedCommentSerializer(serializers.ModelSerializer): + class Meta: + model = BlogPostRelatedComment + fields = ("text") + + class BlogPostSerializer(serializers.ModelSerializer): + comments = serializers.ManyPrimaryKeyRelatedField() + class Meta: + model = BlogPost + fields = ("title", "comments") + + return BlogPostSerializer(data=data) -- cgit v1.2.3 From 18338a37d356faebb0f59bd57b2ba876d66e6b73 Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Sun, 16 Dec 2012 14:49:18 -0500 Subject: Adding PATCH support to Django REST Framework --- rest_framework/tests/decorators.py | 14 ++++++++++++++ rest_framework/tests/generics.py | 13 +++++++++++++ rest_framework/tests/views.py | 4 +++- 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/decorators.py b/rest_framework/tests/decorators.py index 41864d71..a36444cc 100644 --- a/rest_framework/tests/decorators.py +++ b/rest_framework/tests/decorators.py @@ -63,6 +63,20 @@ class DecoratorTestCase(TestCase): response = view(request) self.assertEqual(response.status_code, 405) + # def test_calling_patch_method(self): + + # @api_view(['GET', 'PATCH']) + # def view(request): + # return Response({}) + + # request = self.factory.patch('/') + # response = view(request) + # self.assertEqual(response.status_code, 200) + + # request = self.factory.post('/') + # response = view(request) + # self.assertEqual(response.status_code, 405) + def test_renderer_classes(self): @api_view(['GET']) diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index a8279ef2..1b55a3a5 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -180,6 +180,19 @@ class TestInstanceView(TestCase): updated = self.objects.get(id=1) self.assertEquals(updated.text, 'foobar') + # def test_patch_instance_view(self): + # """ + # PATCH requests to RetrieveUpdateDestroyAPIView should update an object. + # """ + # content = {'text': 'foobar'} + # request = factory.patch('/1', json.dumps(content), + # content_type='application/json') + # response = self.view(request, pk=1).render() + # self.assertEquals(response.status_code, status.HTTP_200_OK) + # self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) + # updated = self.objects.get(id=1) + # self.assertEquals(updated.text, 'foobar') + def test_delete_instance_view(self): """ DELETE requests to RetrieveUpdateDestroyAPIView should delete an object. diff --git a/rest_framework/tests/views.py b/rest_framework/tests/views.py index 43365e07..7cd82656 100644 --- a/rest_framework/tests/views.py +++ b/rest_framework/tests/views.py @@ -18,7 +18,7 @@ class BasicView(APIView): return Response({'method': 'POST', 'data': request.DATA}) -@api_view(['GET', 'POST', 'PUT']) +@api_view(['GET', 'POST', 'PUT', 'PATCH']) def basic_view(request): if request.method == 'GET': return {'method': 'GET'} @@ -26,6 +26,8 @@ def basic_view(request): return {'method': 'POST', 'data': request.DATA} elif request.method == 'PUT': return {'method': 'PUT', 'data': request.DATA} + elif request.method == 'PATCH': + return {'method': 'PATCH', 'data': request.DATA} def sanitise_json_error(error_dict): -- cgit v1.2.3 From 6f6aeadf5f66f1ca788f7e7c6375d64dbfb92b00 Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Mon, 17 Dec 2012 16:31:18 +0200 Subject: CharField in model should be null=True according Django docs All tests should still pass Ref #514 --- rest_framework/tests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 428bf130..3a939a24 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -160,7 +160,7 @@ class Photo(RESTFrameworkModel): # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): - title = models.CharField(max_length=100, blank=True, null=True) + title = models.CharField(max_length=100, blank=True, null=False) # Model for issue #380 -- cgit v1.2.3 From 967f22e7d1d7feef565d32ce67401d13792cbe2b Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Mon, 17 Dec 2012 16:49:45 +0200 Subject: Failing test case for #514 Serializer errors are: {'title': [u'This field is required.']} --- rest_framework/tests/serializer.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 780177aa..7b05d259 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -704,6 +704,10 @@ class BlankFieldTests(TestCase): serializer = self.not_blank_model_serializer_class(data=self.data) self.assertEquals(serializer.is_valid(), False) + def test_create_model_null_field(self): + serializer = self.model_serializer_class(data={}) + self.assertEquals(serializer.is_valid(), True) + #test for issue #460 class SerializerPickleTests(TestCase): -- cgit v1.2.3 From aa72f8d63d2a7b33a2e74eaba216b56c803af70c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 17 Dec 2012 21:59:51 +0000 Subject: Fix bug with M2M in browseable API --- rest_framework/tests/generics.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index a8279ef2..14fa66f9 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -1,3 +1,4 @@ +from django.db import models from django.test import TestCase from django.test.client import RequestFactory from django.utils import simplejson as json @@ -301,3 +302,36 @@ class TestCreateModelWithAutoNowAddField(TestCase): self.assertEquals(response.status_code, status.HTTP_201_CREATED) created = self.objects.get(id=1) self.assertEquals(created.content, 'foobar') + + +# Test for particularly ugly reression with m2m in browseable API +class ClassB(models.Model): + name = models.CharField(max_length=255) + + +class ClassA(models.Model): + name = models.CharField(max_length=255) + childs = models.ManyToManyField(ClassB, blank=True, null=True) + + +class ClassASerializer(serializers.ModelSerializer): + childs = serializers.ManyPrimaryKeyRelatedField(source='childs') + + class Meta: + model = ClassA + + +class ExampleView(generics.ListCreateAPIView): + serializer_class = ClassASerializer + model = ClassA + + +class TestM2MBrowseableAPI(TestCase): + def test_m2m_in_browseable_api(self): + """ + Test for particularly ugly reression with m2m in browseable API + """ + request = factory.get('/', HTTP_ACCEPT='text/html') + view = ExampleView().as_view() + response = view(request).render() + self.assertEquals(response.status_code, status.HTTP_200_OK) -- cgit v1.2.3 From 6693d2d277823c9150077c7c9534b7550dfd192c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 18 Dec 2012 18:21:58 +0000 Subject: Fix for pks returning as strings when set in pre_save. Fixes #482. Thanks to @n8agrin for the bug report. --- rest_framework/tests/generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 14fa66f9..7c24d84e 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -175,7 +175,7 @@ class TestInstanceView(TestCase): content = {'text': 'foobar'} request = factory.put('/1', json.dumps(content), content_type='application/json') - response = self.view(request, pk=1).render() + response = self.view(request, pk='1').render() self.assertEquals(response.status_code, status.HTTP_200_OK) self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) updated = self.objects.get(id=1) -- cgit v1.2.3 From ab86990ac8a735aa3ba4d858040d7ea022321b46 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 18 Dec 2012 19:20:31 +0000 Subject: HyperlinkedRealtedField tests. Refs #442. --- rest_framework/tests/hyperlink_relations.py | 358 ++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 rest_framework/tests/hyperlink_relations.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlink_relations.py b/rest_framework/tests/hyperlink_relations.py new file mode 100644 index 00000000..8f023873 --- /dev/null +++ b/rest_framework/tests/hyperlink_relations.py @@ -0,0 +1,358 @@ +from django.conf.urls import patterns, url +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +def dummy_view(request, pk): + pass + +urlpatterns = patterns('', + url(r'^manytomanysource/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanysource-detail'), + url(r'^manytomanytarget/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanytarget-detail'), + url(r'^foreignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeysource-detail'), + url(r'^foreignkeytarget/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeytarget-detail'), + url(r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableforeignkeysource-detail'), +) + + +# ManyToMany + +class ManyToManyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ManyToManySource(models.Model): + name = models.CharField(max_length=100) + targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') + + +class ManyToManyTargetSerializer(serializers.HyperlinkedModelSerializer): + sources = serializers.ManyHyperlinkedRelatedField(view_name='manytomanysource-detail') + + class Meta: + model = ManyToManyTarget + + +class ManyToManySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = ManyToManySource + + +# ForeignKey + +class ForeignKeyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer): + sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail', read_only=True) + + class Meta: + model = ForeignKeyTarget + + +class ForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = ForeignKeySource + + +# Nullable ForeignKey + +class NullableForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') + + +class NullableForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = NullableForeignKeySource + + +# TODO: Add test that .data cannot be accessed prior to .is_valid + +class HyperlinkedManyToManyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + for idx in range(1, 4): + target = ManyToManyTarget(name='target-%d' % idx) + target.save() + source = ManyToManySource(name='source-%d' % idx) + source.save() + for target in ManyToManyTarget.objects.all(): + source.targets.add(target) + + def test_many_to_many_retrieve(self): + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_retrieve(self): + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_update(self): + data = {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + instance = ManyToManySource.objects.get(pk=1) + serializer = ManyToManySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_update(self): + data = {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']} + instance = ManyToManyTarget.objects.get(pk=1) + serializer = ManyToManyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 1 is updated, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} + + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_create(self): + data = {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} + serializer = ManyToManySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is added, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, + {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_create(self): + data = {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} + serializer = ManyToManyTargetSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'target-4') + + # Ensure target 4 is added, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']}, + {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} + ] + self.assertEquals(serializer.data, expected) + + +class HyperlinkedForeignKeyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + new_target = ForeignKeyTarget(name='target-2') + new_target.save() + for idx in range(1, 4): + source = ForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_retrieve(self): + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_foreign_key_retrieve(self): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']}, + {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update(self): + data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'}, + {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_invalid_null(self): + data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': None} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) + + +class HyperlinkedNullableForeignKeyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + for idx in range(1, 4): + source = NullableForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_create_with_valid_null(self): + data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_create_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': ''} + expected_data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, expected_data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_null(self): + data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': ''} + expected_data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, expected_data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + ] + self.assertEquals(serializer.data, expected) + + # reverse foreign keys MUST be read_only + # In the general case they do not provide .remove() or .clear() + # and cannot be arbitrarily set. + + # def test_reverse_foreign_key_update(self): + # data = {'id': 1, 'name': u'target-1', 'sources': [1]} + # instance = ForeignKeyTarget.objects.get(pk=1) + # serializer = ForeignKeyTargetSerializer(instance, data=data) + # self.assertTrue(serializer.is_valid()) + # self.assertEquals(serializer.data, data) + # serializer.save() + + # # Ensure target 1 is updated, and everything else is as expected + # queryset = ForeignKeyTarget.objects.all() + # serializer = ForeignKeyTargetSerializer(queryset) + # expected = [ + # {'id': 1, 'name': u'target-1', 'sources': [1]}, + # {'id': 2, 'name': u'target-2', 'sources': []}, + # ] + # self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From 24e14b7d53e43f1574971ff5b6eee6d0185df23a Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 14 Nov 2012 12:42:30 -0800 Subject: Add tests for retrieving/updating reverse fks --- rest_framework/tests/nested_relations.py | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 rest_framework/tests/nested_relations.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py new file mode 100644 index 00000000..35e75bb0 --- /dev/null +++ b/rest_framework/tests/nested_relations.py @@ -0,0 +1,68 @@ +from copy import deepcopy +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +# ForeignKey + +class ForeignKeyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +class ForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + model = ForeignKeySource + + +class ForeignKeyTargetSerializer(serializers.ModelSerializer): + sources = ForeignKeySourceSerializer() + + class Meta: + model = ForeignKeyTarget + + +class ReverseForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + new_target = ForeignKeyTarget(name='target-2') + new_target.save() + for idx in range(1, 4): + source = ForeignKeySource(name='source-%d' % idx, target=target) + source.save() + self.target_data = {'id': 1, 'name': u'target-1', 'sources': [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + ]} + self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} + self.data = [self.target_data, self.new_target_data] + + def test_reverse_foreign_key_retrieve(self): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + self.assertEquals(serializer.data, self.data) + + def test_reverse_foreign_key_update(self): + data = deepcopy(self.target_data) + data['sources'][0]['name'] = 'source-1-changed' + data['sources'][2]['name'] = 'source-3-changed' + instance = ForeignKeyTarget.objects.get(pk=1) + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 1 is updated, and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = deepcopy(self.data) + expected[0]['sources'][0]['name'] = 'source-1-changed' + expected[0]['sources'][2]['name'] = 'source-3-changed' + self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From f92c5b28ade6d01f0b52fe59bbc8cdbf44080e92 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 14 Nov 2012 13:39:54 -0800 Subject: Add test for creating a reverse fk relation --- rest_framework/tests/nested_relations.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py index 35e75bb0..b5daea89 100644 --- a/rest_framework/tests/nested_relations.py +++ b/rest_framework/tests/nested_relations.py @@ -49,6 +49,22 @@ class ReverseForeignKeyTests(TestCase): serializer = ForeignKeyTargetSerializer(queryset) self.assertEquals(serializer.data, self.data) + def test_reverse_foreign_key_create(self): + data = deepcopy(self.new_target_data) + data['sources'].append({'name': u'source-4', 'target': 2}) + instance = ForeignKeyTarget.objects.get(pk=2) + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 2 has new source and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = deepcopy(self.data) + expected[1]['sources'].append({'id': 4, 'name': 'source-4', 'target': 2}) + self.assertEquals(serializer.data, expected) + def test_reverse_foreign_key_update(self): data = deepcopy(self.target_data) data['sources'][0]['name'] = 'source-1-changed' -- cgit v1.2.3 From cbf342900515859f4322d273a7ef8988a119f507 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 14 Nov 2012 15:15:35 -0800 Subject: Add test for deleting a reverse fk relation --- rest_framework/tests/nested_relations.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py index b5daea89..93d95622 100644 --- a/rest_framework/tests/nested_relations.py +++ b/rest_framework/tests/nested_relations.py @@ -82,3 +82,19 @@ class ReverseForeignKeyTests(TestCase): expected[0]['sources'][0]['name'] = 'source-1-changed' expected[0]['sources'][2]['name'] = 'source-3-changed' self.assertEquals(serializer.data, expected) + + def test_reverse_foreign_key_delete(self): + data = deepcopy(self.target_data) + del data['sources'][2] + instance = ForeignKeyTarget.objects.get(pk=1) + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 1 has 2 sources and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = deepcopy(self.data) + del expected[0]['sources'][2] + self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From 2910bfb5275c88d30aa73e580a35a46684177d38 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 14 Nov 2012 15:27:38 -0800 Subject: Add two functions for more DRY reverse fk tests --- rest_framework/tests/nested_relations.py | 40 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 23 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py index 93d95622..c88bd2b3 100644 --- a/rest_framework/tests/nested_relations.py +++ b/rest_framework/tests/nested_relations.py @@ -44,57 +44,51 @@ class ReverseForeignKeyTests(TestCase): self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} self.data = [self.target_data, self.new_target_data] - def test_reverse_foreign_key_retrieve(self): + def save_serialized_target(self, instance, data): + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + def check_serialized_targets(self, data): queryset = ForeignKeyTarget.objects.all() serializer = ForeignKeyTargetSerializer(queryset) - self.assertEquals(serializer.data, self.data) + self.assertEquals(serializer.data, data) + + def test_reverse_foreign_key_retrieve(self): + self.check_serialized_targets(self.data) def test_reverse_foreign_key_create(self): data = deepcopy(self.new_target_data) data['sources'].append({'name': u'source-4', 'target': 2}) instance = ForeignKeyTarget.objects.get(pk=2) - serializer = ForeignKeyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() + self.save_serialized_target(instance, data) # Ensure target 2 has new source and everything else is as expected - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) expected = deepcopy(self.data) expected[1]['sources'].append({'id': 4, 'name': 'source-4', 'target': 2}) - self.assertEquals(serializer.data, expected) + self.check_serialized_targets(expected) def test_reverse_foreign_key_update(self): data = deepcopy(self.target_data) data['sources'][0]['name'] = 'source-1-changed' data['sources'][2]['name'] = 'source-3-changed' instance = ForeignKeyTarget.objects.get(pk=1) - serializer = ForeignKeyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() + self.save_serialized_target(instance, data) # Ensure target 1 is updated, and everything else is as expected - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) expected = deepcopy(self.data) expected[0]['sources'][0]['name'] = 'source-1-changed' expected[0]['sources'][2]['name'] = 'source-3-changed' - self.assertEquals(serializer.data, expected) + self.check_serialized_targets(expected) def test_reverse_foreign_key_delete(self): data = deepcopy(self.target_data) del data['sources'][2] instance = ForeignKeyTarget.objects.get(pk=1) - serializer = ForeignKeyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() + self.save_serialized_target(instance, data) # Ensure target 1 has 2 sources and everything else is as expected - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) expected = deepcopy(self.data) del expected[0]['sources'][2] - self.assertEquals(serializer.data, expected) + self.check_serialized_targets(expected) -- cgit v1.2.3 From 8a41d4aa5411560aabc5c198976b7df6580e6143 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Fri, 16 Nov 2012 23:01:03 -0800 Subject: Fix assertion for nested create test (missing id) --- rest_framework/tests/nested_relations.py | 1 - 1 file changed, 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py index c88bd2b3..0d4d6ce8 100644 --- a/rest_framework/tests/nested_relations.py +++ b/rest_framework/tests/nested_relations.py @@ -47,7 +47,6 @@ class ReverseForeignKeyTests(TestCase): def save_serialized_target(self, instance, data): serializer = ForeignKeyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() def check_serialized_targets(self, data): -- cgit v1.2.3 From c6a6d7ac15b351e2d81685abefd44542367b6e6f Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Wed, 19 Dec 2012 07:33:49 -0800 Subject: remove all but the 'read' nested serializer tests --- rest_framework/tests/nested_relations.py | 40 -------------------------------- 1 file changed, 40 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py index 0d4d6ce8..b9022cac 100644 --- a/rest_framework/tests/nested_relations.py +++ b/rest_framework/tests/nested_relations.py @@ -44,11 +44,6 @@ class ReverseForeignKeyTests(TestCase): self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} self.data = [self.target_data, self.new_target_data] - def save_serialized_target(self, instance, data): - serializer = ForeignKeyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - serializer.save() - def check_serialized_targets(self, data): queryset = ForeignKeyTarget.objects.all() serializer = ForeignKeyTargetSerializer(queryset) @@ -56,38 +51,3 @@ class ReverseForeignKeyTests(TestCase): def test_reverse_foreign_key_retrieve(self): self.check_serialized_targets(self.data) - - def test_reverse_foreign_key_create(self): - data = deepcopy(self.new_target_data) - data['sources'].append({'name': u'source-4', 'target': 2}) - instance = ForeignKeyTarget.objects.get(pk=2) - self.save_serialized_target(instance, data) - - # Ensure target 2 has new source and everything else is as expected - expected = deepcopy(self.data) - expected[1]['sources'].append({'id': 4, 'name': 'source-4', 'target': 2}) - self.check_serialized_targets(expected) - - def test_reverse_foreign_key_update(self): - data = deepcopy(self.target_data) - data['sources'][0]['name'] = 'source-1-changed' - data['sources'][2]['name'] = 'source-3-changed' - instance = ForeignKeyTarget.objects.get(pk=1) - self.save_serialized_target(instance, data) - - # Ensure target 1 is updated, and everything else is as expected - expected = deepcopy(self.data) - expected[0]['sources'][0]['name'] = 'source-1-changed' - expected[0]['sources'][2]['name'] = 'source-3-changed' - self.check_serialized_targets(expected) - - def test_reverse_foreign_key_delete(self): - data = deepcopy(self.target_data) - del data['sources'][2] - instance = ForeignKeyTarget.objects.get(pk=1) - self.save_serialized_target(instance, data) - - # Ensure target 1 has 2 sources and everything else is as expected - expected = deepcopy(self.data) - del expected[0]['sources'][2] - self.check_serialized_targets(expected) -- cgit v1.2.3 From c13f132a21f5a0902cef74dfea12e586561774ca Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Tue, 18 Dec 2012 14:09:58 +0200 Subject: Failing test with partial serializer and foreign keys --- rest_framework/tests/serializer.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 780177aa..693c81c2 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -297,6 +297,38 @@ class ModelValidationTests(TestCase): self.assertFalse(second_serializer.is_valid()) self.assertEqual(second_serializer.errors, {'title': [u'Album with this Title already exists.']}) + def test_foreign_key_with_partial(self): + """ + Test ModelSerializer validation with partial=True + + Specifically test foreign key validation. + """ + + album = Album(title='test') + album.save() + + class PhotoSerializer(serializers.ModelSerializer): + class Meta: + model = Photo + + photo_serializer = PhotoSerializer(data={'description': 'test', 'album': album.pk}) + self.assertTrue(photo_serializer.is_valid()) + photo = photo_serializer.save() + + # Updating only the album (foreign key) + photo_serializer = PhotoSerializer(instance=photo, data={'album': album.pk}, partial=True) + self.assertTrue(photo_serializer.is_valid()) + self.assertTrue(photo_serializer.save()) + + # Updating only the description + photo_serializer = PhotoSerializer(instance=photo, + data={'description': 'new'}, + partial=True) + + self.assertTrue(photo_serializer.is_valid()) + self.assertTrue(photo_serializer.save()) + + class RegexValidationTest(TestCase): def test_create_failed(self): -- cgit v1.2.3 From d90d5380d730b992b1b59aaf9d1f89fbbbba0f9f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 19 Dec 2012 22:05:00 +0000 Subject: pep8 --- rest_framework/tests/renderers.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index 9be4b114..fb843676 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -444,19 +444,19 @@ class CacheRenderTest(TestCase): return if state == None: return - if isinstance(state,tuple): - if not isinstance(state[0],dict): - state=state[1] + if isinstance(state, tuple): + if not isinstance(state[0], dict): + state = state[1] else: - state=state[0].update(state[1]) + state = state[0].update(state[1]) result = {} for i in state: try: - pickle.dumps(state[i],protocol=2) + pickle.dumps(state[i], protocol=2) except pickle.PicklingError: if not state[i] in seen: seen.append(state[i]) - result[i] = cls._get_pickling_errors(state[i],seen) + result[i] = cls._get_pickling_errors(state[i], seen) return result def http_resp(self, http_method, url): -- cgit v1.2.3 From a493c83248535c9fa7f78815b16bce7e88bf7966 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 19 Dec 2012 23:12:27 +0000 Subject: urls, patterns, include imports move to compat to support incoming 1.3 thru 1.6 import compatability --- rest_framework/tests/authentication.py | 8 +++----- rest_framework/tests/breadcrumbs.py | 2 +- rest_framework/tests/decorators.py | 2 +- rest_framework/tests/htmlrenderer.py | 2 +- rest_framework/tests/hyperlink_relations.py | 2 +- rest_framework/tests/hyperlinkedserializers.py | 2 +- rest_framework/tests/models.py | 5 +++-- rest_framework/tests/renderers.py | 3 +-- rest_framework/tests/request.py | 5 ++--- rest_framework/tests/response.py | 5 +---- rest_framework/tests/reverse.py | 2 +- rest_framework/tests/serializer.py | 4 ++++ rest_framework/tests/testcases.py | 6 ++++-- 13 files changed, 24 insertions(+), 24 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index d498ae3e..838e081b 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -1,15 +1,13 @@ -from django.conf.urls.defaults import patterns from django.contrib.auth.models import User +from django.http import HttpResponse from django.test import Client, TestCase - from django.utils import simplejson as json -from django.http import HttpResponse -from rest_framework.views import APIView from rest_framework import permissions - from rest_framework.authtoken.models import Token from rest_framework.authentication import TokenAuthentication +from rest_framework.compat import patterns +from rest_framework.views import APIView import base64 diff --git a/rest_framework/tests/breadcrumbs.py b/rest_framework/tests/breadcrumbs.py index 647ab96d..df891683 100644 --- a/rest_framework/tests/breadcrumbs.py +++ b/rest_framework/tests/breadcrumbs.py @@ -1,5 +1,5 @@ -from django.conf.urls.defaults import patterns, url from django.test import TestCase +from rest_framework.compat import patterns, url from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.views import APIView diff --git a/rest_framework/tests/decorators.py b/rest_framework/tests/decorators.py index 41864d71..8079c8cb 100644 --- a/rest_framework/tests/decorators.py +++ b/rest_framework/tests/decorators.py @@ -1,7 +1,7 @@ from django.test import TestCase +from django.test.client import RequestFactory from rest_framework import status from rest_framework.response import Response -from django.test.client import RequestFactory from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from rest_framework.authentication import BasicAuthentication diff --git a/rest_framework/tests/htmlrenderer.py b/rest_framework/tests/htmlrenderer.py index 4caed59e..54096206 100644 --- a/rest_framework/tests/htmlrenderer.py +++ b/rest_framework/tests/htmlrenderer.py @@ -1,9 +1,9 @@ from django.core.exceptions import PermissionDenied -from django.conf.urls.defaults import patterns, url from django.http import Http404 from django.test import TestCase from django.template import TemplateDoesNotExist, Template import django.template.loader +from rest_framework.compat import patterns, url from rest_framework.decorators import api_view, renderer_classes from rest_framework.renderers import TemplateHTMLRenderer from rest_framework.response import Response diff --git a/rest_framework/tests/hyperlink_relations.py b/rest_framework/tests/hyperlink_relations.py index 8f023873..9e8ecf70 100644 --- a/rest_framework/tests/hyperlink_relations.py +++ b/rest_framework/tests/hyperlink_relations.py @@ -1,7 +1,7 @@ -from django.conf.urls import patterns, url from django.db import models from django.test import TestCase from rest_framework import serializers +from rest_framework.compat import patterns, url def dummy_view(request, pk): diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index 24bf61bf..ee4d8e57 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -1,8 +1,8 @@ -from django.conf.urls.defaults import patterns, url from django.test import TestCase from django.test.client import RequestFactory from django.utils import simplejson as json from rest_framework import generics, status, serializers +from rest_framework.compat import patterns, url from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel factory = RequestFactory() diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 1b1def30..0759650a 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -52,9 +52,10 @@ class RESTFrameworkModel(models.Model): class HasPositiveIntegerAsChoice(RESTFrameworkModel): - some_choices = ((1,'A'),(2,'B'),(3,'C')) + some_choices = ((1, 'A'), (2, 'B'), (3, 'C')) some_integer = models.PositiveIntegerField(choices=some_choices) + class Anchor(RESTFrameworkModel): text = models.CharField(max_length=100, default='anchor') @@ -164,7 +165,7 @@ class Photo(RESTFrameworkModel): # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): - title = models.CharField(max_length=100, blank=True, null=True) + title = models.CharField(max_length=100, blank=True, null=False) # Model for issue #380 diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index fb843676..c1b4e624 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -1,13 +1,12 @@ import pickle import re -from django.conf.urls.defaults import patterns, url, include from django.core.cache import cache from django.test import TestCase from django.test.client import RequestFactory from rest_framework import status, permissions -from rest_framework.compat import yaml +from rest_framework.compat import yaml, patterns, url, include from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index 2850992d..2eb34cea 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -1,16 +1,15 @@ """ Tests for content parsing, and form-overloaded content parsing. """ -from django.conf.urls.defaults import patterns from django.contrib.auth.models import User from django.contrib.auth import authenticate, login, logout from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, Client +from django.test.client import RequestFactory from django.utils import simplejson as json - from rest_framework import status from rest_framework.authentication import SessionAuthentication -from django.test.client import RequestFactory +from rest_framework.compat import patterns from rest_framework.parsers import ( BaseParser, FormParser, diff --git a/rest_framework/tests/response.py b/rest_framework/tests/response.py index d7b75450..875f4d42 100644 --- a/rest_framework/tests/response.py +++ b/rest_framework/tests/response.py @@ -1,8 +1,5 @@ -import unittest - -from django.conf.urls.defaults import patterns, url, include from django.test import TestCase - +from rest_framework.compat import patterns, url, include from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status diff --git a/rest_framework/tests/reverse.py b/rest_framework/tests/reverse.py index fd9a7d64..8c86e1fb 100644 --- a/rest_framework/tests/reverse.py +++ b/rest_framework/tests/reverse.py @@ -1,6 +1,6 @@ -from django.conf.urls.defaults import patterns, url from django.test import TestCase from django.test.client import RequestFactory +from rest_framework.compat import patterns, url from rest_framework.reverse import reverse factory = RequestFactory() diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 7f2c27b0..6ea4b424 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -699,6 +699,10 @@ class BlankFieldTests(TestCase): serializer = self.model_serializer_class(data=self.data) self.assertEquals(serializer.is_valid(), True) + def test_create_model_null_field(self): + serializer = self.model_serializer_class(data={'title': None}) + self.assertEquals(serializer.is_valid(), True) + def test_create_not_blank_field(self): """ Test to ensure blank data in a field not marked as blank=True diff --git a/rest_framework/tests/testcases.py b/rest_framework/tests/testcases.py index c90224aa..97f492ff 100644 --- a/rest_framework/tests/testcases.py +++ b/rest_framework/tests/testcases.py @@ -6,6 +6,7 @@ from django.test import TestCase NO_SETTING = ('!', None) + class TestSettingsManager(object): """ A class which can modify some Django settings temporarily for a @@ -19,7 +20,7 @@ class TestSettingsManager(object): self._original_settings = {} def set(self, **kwargs): - for k,v in kwargs.iteritems(): + for k, v in kwargs.iteritems(): self._original_settings.setdefault(k, getattr(settings, k, NO_SETTING)) setattr(settings, k, v) @@ -31,7 +32,7 @@ class TestSettingsManager(object): call_command('syncdb', verbosity=0) def revert(self): - for k,v in self._original_settings.iteritems(): + for k, v in self._original_settings.iteritems(): if v == NO_SETTING: delattr(settings, k) else: @@ -57,6 +58,7 @@ class SettingsTestCase(TestCase): def tearDown(self): self.settings_manager.revert() + class TestModelsTestCase(SettingsTestCase): def setUp(self, *args, **kwargs): installed_apps = tuple(settings.INSTALLED_APPS) + ('rest_framework.tests',) -- cgit v1.2.3 From 2b5deefe567d46315e9233fd405328e762e4ce07 Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Thu, 20 Dec 2012 00:27:29 -0500 Subject: Subclass Django's RequestFactory to provide PATCH support --- rest_framework/tests/utils.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 rest_framework/tests/utils.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/utils.py b/rest_framework/tests/utils.py new file mode 100644 index 00000000..d7f14156 --- /dev/null +++ b/rest_framework/tests/utils.py @@ -0,0 +1,27 @@ +from django.test.client import RequestFactory, FakePayload +from django.test.client import MULTIPART_CONTENT +from urlparse import urlparse + + +class DRFRequestFactory(RequestFactory): + + def __init__(self, **defaults): + super(DRFRequestFactory, self).__init__(**defaults) + + def patch(self, path, data={}, content_type=MULTIPART_CONTENT, + **extra): + "Construct a PATCH request." + + patch_data = self._encode_data(data, content_type) + + parsed = urlparse(path) + r = { + 'CONTENT_LENGTH': len(patch_data), + 'CONTENT_TYPE': content_type, + 'PATH_INFO': self._get_path(parsed), + 'QUERY_STRING': parsed[4], + 'REQUEST_METHOD': 'PATCH', + 'wsgi.input': FakePayload(patch_data), + } + r.update(extra) + return self.request(**r) -- cgit v1.2.3 From e61eab43f46dd100cf3efe9262474046678951a3 Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Thu, 20 Dec 2012 00:28:01 -0500 Subject: Adjust PATCH test cases to use the new DRFRequestFactory --- rest_framework/tests/decorators.py | 26 ++++++++++++++------------ rest_framework/tests/generics.py | 31 ++++++++++++++++--------------- 2 files changed, 30 insertions(+), 27 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/decorators.py b/rest_framework/tests/decorators.py index a36444cc..c2387f58 100644 --- a/rest_framework/tests/decorators.py +++ b/rest_framework/tests/decorators.py @@ -1,7 +1,7 @@ from django.test import TestCase from rest_framework import status from rest_framework.response import Response -from django.test.client import RequestFactory +# from django.test.client import RequestFactory from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from rest_framework.authentication import BasicAuthentication @@ -17,11 +17,13 @@ from rest_framework.decorators import ( permission_classes, ) +from rest_framework.tests.utils import DRFRequestFactory + class DecoratorTestCase(TestCase): def setUp(self): - self.factory = RequestFactory() + self.factory = DRFRequestFactory() def _finalize_response(self, request, response, *args, **kwargs): response.request = request @@ -63,19 +65,19 @@ class DecoratorTestCase(TestCase): response = view(request) self.assertEqual(response.status_code, 405) - # def test_calling_patch_method(self): + def test_calling_patch_method(self): - # @api_view(['GET', 'PATCH']) - # def view(request): - # return Response({}) + @api_view(['GET', 'PATCH']) + def view(request): + return Response({}) - # request = self.factory.patch('/') - # response = view(request) - # self.assertEqual(response.status_code, 200) + request = self.factory.patch('/') + response = view(request) + self.assertEqual(response.status_code, 200) - # request = self.factory.post('/') - # response = view(request) - # self.assertEqual(response.status_code, 405) + request = self.factory.post('/') + response = view(request) + self.assertEqual(response.status_code, 405) def test_renderer_classes(self): diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 1b55a3a5..a5432d11 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -1,11 +1,11 @@ from django.test import TestCase -from django.test.client import RequestFactory from django.utils import simplejson as json from rest_framework import generics, serializers, status +from rest_framework.tests.utils import DRFRequestFactory from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel -factory = RequestFactory() +factory = DRFRequestFactory() class RootView(generics.ListCreateAPIView): @@ -15,7 +15,7 @@ class RootView(generics.ListCreateAPIView): model = BasicModel -class InstanceView(generics.RetrieveUpdateDestroyAPIView): +class InstanceView(generics.RetrievePartialUpdateDestroyAPIView): """ Example description for OPTIONS. """ @@ -180,18 +180,19 @@ class TestInstanceView(TestCase): updated = self.objects.get(id=1) self.assertEquals(updated.text, 'foobar') - # def test_patch_instance_view(self): - # """ - # PATCH requests to RetrieveUpdateDestroyAPIView should update an object. - # """ - # content = {'text': 'foobar'} - # request = factory.patch('/1', json.dumps(content), - # content_type='application/json') - # response = self.view(request, pk=1).render() - # self.assertEquals(response.status_code, status.HTTP_200_OK) - # self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) - # updated = self.objects.get(id=1) - # self.assertEquals(updated.text, 'foobar') + def test_patch_instance_view(self): + """ + PATCH requests to RetrieveUpdateDestroyAPIView should update an object. + """ + content = {'text': 'foobar'} + request = factory.patch('/1', json.dumps(content), + content_type='application/json') + + response = self.view(request, pk=1).render() + self.assertEquals(response.status_code, status.HTTP_200_OK) + self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) + updated = self.objects.get(id=1) + self.assertEquals(updated.text, 'foobar') def test_delete_instance_view(self): """ -- cgit v1.2.3 From 125f027d2d124e2a483406d9d70e447b8634350c Mon Sep 17 00:00:00 2001 From: Mark Hughes Date: Thu, 20 Dec 2012 23:48:10 +0000 Subject: Added setter to the auth property --- rest_framework/tests/request.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index 2eb34cea..1f05ff8f 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -303,3 +303,11 @@ class TestUserSetter(TestCase): self.assertFalse(self.request.user.is_anonymous()) logout(self.request) self.assertTrue(self.request.user.is_anonymous()) + + +class TestAuthSetter(TestCase): + + def test_auth_can_be_set(self): + request = Request(factory.get('/')) + request.auth = 'DUMMY' + self.assertEqual(request.auth, 'DUMMY') -- cgit v1.2.3 From 83feda6a69317025a0574af630faeaf254b99aed Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 21 Dec 2012 09:10:16 +0000 Subject: Rename relationship tests so they show up together --- rest_framework/tests/hyperlink_relations.py | 358 ---------------------------- rest_framework/tests/nested_relations.py | 53 ---- rest_framework/tests/pk_relations.py | 338 -------------------------- rest_framework/tests/relations_hyperlink.py | 358 ++++++++++++++++++++++++++++ rest_framework/tests/relations_nested.py | 52 ++++ rest_framework/tests/relations_pk.py | 338 ++++++++++++++++++++++++++ 6 files changed, 748 insertions(+), 749 deletions(-) delete mode 100644 rest_framework/tests/hyperlink_relations.py delete mode 100644 rest_framework/tests/nested_relations.py delete mode 100644 rest_framework/tests/pk_relations.py create mode 100644 rest_framework/tests/relations_hyperlink.py create mode 100644 rest_framework/tests/relations_nested.py create mode 100644 rest_framework/tests/relations_pk.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/hyperlink_relations.py b/rest_framework/tests/hyperlink_relations.py deleted file mode 100644 index 9e8ecf70..00000000 --- a/rest_framework/tests/hyperlink_relations.py +++ /dev/null @@ -1,358 +0,0 @@ -from django.db import models -from django.test import TestCase -from rest_framework import serializers -from rest_framework.compat import patterns, url - - -def dummy_view(request, pk): - pass - -urlpatterns = patterns('', - url(r'^manytomanysource/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanysource-detail'), - url(r'^manytomanytarget/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanytarget-detail'), - url(r'^foreignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeysource-detail'), - url(r'^foreignkeytarget/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeytarget-detail'), - url(r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableforeignkeysource-detail'), -) - - -# ManyToMany - -class ManyToManyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ManyToManySource(models.Model): - name = models.CharField(max_length=100) - targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') - - -class ManyToManyTargetSerializer(serializers.HyperlinkedModelSerializer): - sources = serializers.ManyHyperlinkedRelatedField(view_name='manytomanysource-detail') - - class Meta: - model = ManyToManyTarget - - -class ManyToManySourceSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = ManyToManySource - - -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') - - -class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer): - sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail', read_only=True) - - class Meta: - model = ForeignKeyTarget - - -class ForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = ForeignKeySource - - -# Nullable ForeignKey - -class NullableForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, - related_name='nullable_sources') - - -class NullableForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = NullableForeignKeySource - - -# TODO: Add test that .data cannot be accessed prior to .is_valid - -class HyperlinkedManyToManyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' - - def setUp(self): - for idx in range(1, 4): - target = ManyToManyTarget(name='target-%d' % idx) - target.save() - source = ManyToManySource(name='source-%d' % idx) - source.save() - for target in ManyToManyTarget.objects.all(): - source.targets.add(target) - - def test_many_to_many_retrieve(self): - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, - {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, - {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_retrieve(self): - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, - {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, - {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} - ] - self.assertEquals(serializer.data, expected) - - def test_many_to_many_update(self): - data = {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} - instance = ManyToManySource.objects.get(pk=1) - serializer = ManyToManySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, - {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, - {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_update(self): - data = {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']} - instance = ManyToManyTarget.objects.get(pk=1) - serializer = ManyToManyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure target 1 is updated, and everything else is as expected - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']}, - {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, - {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} - - ] - self.assertEquals(serializer.data, expected) - - def test_many_to_many_create(self): - data = {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} - serializer = ManyToManySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is added, and everything else is as expected - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, - {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, - {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, - {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_create(self): - data = {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} - serializer = ManyToManyTargetSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'target-4') - - # Ensure target 4 is added, and everything else is as expected - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, - {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, - {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']}, - {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} - ] - self.assertEquals(serializer.data, expected) - - -class HyperlinkedForeignKeyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' - - def setUp(self): - target = ForeignKeyTarget(name='target-1') - target.save() - new_target = ForeignKeyTarget(name='target-2') - new_target.save() - for idx in range(1, 4): - source = ForeignKeySource(name='source-%d' % idx, target=target) - source.save() - - def test_foreign_key_retrieve(self): - queryset = ForeignKeySource.objects.all() - serializer = ForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, - {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_foreign_key_retrieve(self): - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) - expected = [ - {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']}, - {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update(self): - data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'} - instance = ForeignKeySource.objects.get(pk=1) - serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = ForeignKeySource.objects.all() - serializer = ForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'}, - {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_invalid_null(self): - data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': None} - instance = ForeignKeySource.objects.get(pk=1) - serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) - - -class HyperlinkedNullableForeignKeyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' - - def setUp(self): - target = ForeignKeyTarget(name='target-1') - target.save() - for idx in range(1, 4): - source = NullableForeignKeySource(name='source-%d' % idx, target=target) - source.save() - - def test_foreign_key_create_with_valid_null(self): - data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} - serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is created, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_create_with_valid_emptystring(self): - """ - The emptystring should be interpreted as null in the context - of relationships. - """ - data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': ''} - expected_data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} - serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, expected_data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is created, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_valid_null(self): - data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} - instance = NullableForeignKeySource.objects.get(pk=1) - serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, - {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_valid_emptystring(self): - """ - The emptystring should be interpreted as null in the context - of relationships. - """ - data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': ''} - expected_data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} - instance = NullableForeignKeySource.objects.get(pk=1) - serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, expected_data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, - {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, - ] - self.assertEquals(serializer.data, expected) - - # reverse foreign keys MUST be read_only - # In the general case they do not provide .remove() or .clear() - # and cannot be arbitrarily set. - - # def test_reverse_foreign_key_update(self): - # data = {'id': 1, 'name': u'target-1', 'sources': [1]} - # instance = ForeignKeyTarget.objects.get(pk=1) - # serializer = ForeignKeyTargetSerializer(instance, data=data) - # self.assertTrue(serializer.is_valid()) - # self.assertEquals(serializer.data, data) - # serializer.save() - - # # Ensure target 1 is updated, and everything else is as expected - # queryset = ForeignKeyTarget.objects.all() - # serializer = ForeignKeyTargetSerializer(queryset) - # expected = [ - # {'id': 1, 'name': u'target-1', 'sources': [1]}, - # {'id': 2, 'name': u'target-2', 'sources': []}, - # ] - # self.assertEquals(serializer.data, expected) diff --git a/rest_framework/tests/nested_relations.py b/rest_framework/tests/nested_relations.py deleted file mode 100644 index b9022cac..00000000 --- a/rest_framework/tests/nested_relations.py +++ /dev/null @@ -1,53 +0,0 @@ -from copy import deepcopy -from django.db import models -from django.test import TestCase -from rest_framework import serializers - - -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') - - -class ForeignKeySourceSerializer(serializers.ModelSerializer): - class Meta: - model = ForeignKeySource - - -class ForeignKeyTargetSerializer(serializers.ModelSerializer): - sources = ForeignKeySourceSerializer() - - class Meta: - model = ForeignKeyTarget - - -class ReverseForeignKeyTests(TestCase): - def setUp(self): - target = ForeignKeyTarget(name='target-1') - target.save() - new_target = ForeignKeyTarget(name='target-2') - new_target.save() - for idx in range(1, 4): - source = ForeignKeySource(name='source-%d' % idx, target=target) - source.save() - self.target_data = {'id': 1, 'name': u'target-1', 'sources': [ - {'id': 1, 'name': u'source-1', 'target': 1}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1}, - ]} - self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} - self.data = [self.target_data, self.new_target_data] - - def check_serialized_targets(self, data): - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) - self.assertEquals(serializer.data, data) - - def test_reverse_foreign_key_retrieve(self): - self.check_serialized_targets(self.data) diff --git a/rest_framework/tests/pk_relations.py b/rest_framework/tests/pk_relations.py deleted file mode 100644 index e3360939..00000000 --- a/rest_framework/tests/pk_relations.py +++ /dev/null @@ -1,338 +0,0 @@ -from django.db import models -from django.test import TestCase -from rest_framework import serializers - - -# ManyToMany - -class ManyToManyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ManyToManySource(models.Model): - name = models.CharField(max_length=100) - targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') - - -class ManyToManyTargetSerializer(serializers.ModelSerializer): - sources = serializers.ManyPrimaryKeyRelatedField() - - class Meta: - model = ManyToManyTarget - - -class ManyToManySourceSerializer(serializers.ModelSerializer): - class Meta: - model = ManyToManySource - - -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') - - -class ForeignKeyTargetSerializer(serializers.ModelSerializer): - sources = serializers.ManyPrimaryKeyRelatedField(read_only=True) - - class Meta: - model = ForeignKeyTarget - - -class ForeignKeySourceSerializer(serializers.ModelSerializer): - class Meta: - model = ForeignKeySource - - -# Nullable ForeignKey - -class NullableForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, - related_name='nullable_sources') - - -class NullableForeignKeySourceSerializer(serializers.ModelSerializer): - class Meta: - model = NullableForeignKeySource - - -# TODO: Add test that .data cannot be accessed prior to .is_valid - -class PKManyToManyTests(TestCase): - def setUp(self): - for idx in range(1, 4): - target = ManyToManyTarget(name='target-%d' % idx) - target.save() - source = ManyToManySource(name='source-%d' % idx) - source.save() - for target in ManyToManyTarget.objects.all(): - source.targets.add(target) - - def test_many_to_many_retrieve(self): - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'targets': [1]}, - {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, - {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_retrieve(self): - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, - {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, - {'id': 3, 'name': u'target-3', 'sources': [3]} - ] - self.assertEquals(serializer.data, expected) - - def test_many_to_many_update(self): - data = {'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]} - instance = ManyToManySource.objects.get(pk=1) - serializer = ManyToManySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]}, - {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, - {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_update(self): - data = {'id': 1, 'name': u'target-1', 'sources': [1]} - instance = ManyToManyTarget.objects.get(pk=1) - serializer = ManyToManyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure target 1 is updated, and everything else is as expected - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'id': 1, 'name': u'target-1', 'sources': [1]}, - {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, - {'id': 3, 'name': u'target-3', 'sources': [3]} - ] - self.assertEquals(serializer.data, expected) - - def test_many_to_many_create(self): - data = {'id': 4, 'name': u'source-4', 'targets': [1, 3]} - serializer = ManyToManySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is added, and everything else is as expected - queryset = ManyToManySource.objects.all() - serializer = ManyToManySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'targets': [1]}, - {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, - {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]}, - {'id': 4, 'name': u'source-4', 'targets': [1, 3]}, - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_many_to_many_create(self): - data = {'id': 4, 'name': u'target-4', 'sources': [1, 3]} - serializer = ManyToManyTargetSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'target-4') - - # Ensure target 4 is added, and everything else is as expected - queryset = ManyToManyTarget.objects.all() - serializer = ManyToManyTargetSerializer(queryset) - expected = [ - {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, - {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, - {'id': 3, 'name': u'target-3', 'sources': [3]}, - {'id': 4, 'name': u'target-4', 'sources': [1, 3]} - ] - self.assertEquals(serializer.data, expected) - - -class PKForeignKeyTests(TestCase): - def setUp(self): - target = ForeignKeyTarget(name='target-1') - target.save() - new_target = ForeignKeyTarget(name='target-2') - new_target.save() - for idx in range(1, 4): - source = ForeignKeySource(name='source-%d' % idx, target=target) - source.save() - - def test_foreign_key_retrieve(self): - queryset = ForeignKeySource.objects.all() - serializer = ForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': 1}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} - ] - self.assertEquals(serializer.data, expected) - - def test_reverse_foreign_key_retrieve(self): - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) - expected = [ - {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, - {'id': 2, 'name': u'target-2', 'sources': []}, - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update(self): - data = {'id': 1, 'name': u'source-1', 'target': 2} - instance = ForeignKeySource.objects.get(pk=1) - serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = ForeignKeySource.objects.all() - serializer = ForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': 2}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_invalid_null(self): - data = {'id': 1, 'name': u'source-1', 'target': None} - instance = ForeignKeySource.objects.get(pk=1) - serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) - - -class PKNullableForeignKeyTests(TestCase): - def setUp(self): - target = ForeignKeyTarget(name='target-1') - target.save() - for idx in range(1, 4): - source = NullableForeignKeySource(name='source-%d' % idx, target=target) - source.save() - - def test_foreign_key_create_with_valid_null(self): - data = {'id': 4, 'name': u'source-4', 'target': None} - serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is created, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': 1}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1}, - {'id': 4, 'name': u'source-4', 'target': None} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_create_with_valid_emptystring(self): - """ - The emptystring should be interpreted as null in the context - of relationships. - """ - data = {'id': 4, 'name': u'source-4', 'target': ''} - expected_data = {'id': 4, 'name': u'source-4', 'target': None} - serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) - obj = serializer.save() - self.assertEquals(serializer.data, expected_data) - self.assertEqual(obj.name, u'source-4') - - # Ensure source 4 is created, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': 1}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1}, - {'id': 4, 'name': u'source-4', 'target': None} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_valid_null(self): - data = {'id': 1, 'name': u'source-1', 'target': None} - instance = NullableForeignKeySource.objects.get(pk=1) - serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': None}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} - ] - self.assertEquals(serializer.data, expected) - - def test_foreign_key_update_with_valid_emptystring(self): - """ - The emptystring should be interpreted as null in the context - of relationships. - """ - data = {'id': 1, 'name': u'source-1', 'target': ''} - expected_data = {'id': 1, 'name': u'source-1', 'target': None} - instance = NullableForeignKeySource.objects.get(pk=1) - serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, expected_data) - serializer.save() - - # Ensure source 1 is updated, and everything else is as expected - queryset = NullableForeignKeySource.objects.all() - serializer = NullableForeignKeySourceSerializer(queryset) - expected = [ - {'id': 1, 'name': u'source-1', 'target': None}, - {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} - ] - self.assertEquals(serializer.data, expected) - - # reverse foreign keys MUST be read_only - # In the general case they do not provide .remove() or .clear() - # and cannot be arbitrarily set. - - # def test_reverse_foreign_key_update(self): - # data = {'id': 1, 'name': u'target-1', 'sources': [1]} - # instance = ForeignKeyTarget.objects.get(pk=1) - # serializer = ForeignKeyTargetSerializer(instance, data=data) - # self.assertTrue(serializer.is_valid()) - # self.assertEquals(serializer.data, data) - # serializer.save() - - # # Ensure target 1 is updated, and everything else is as expected - # queryset = ForeignKeyTarget.objects.all() - # serializer = ForeignKeyTargetSerializer(queryset) - # expected = [ - # {'id': 1, 'name': u'target-1', 'sources': [1]}, - # {'id': 2, 'name': u'target-2', 'sources': []}, - # ] - # self.assertEquals(serializer.data, expected) diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py new file mode 100644 index 00000000..9e8ecf70 --- /dev/null +++ b/rest_framework/tests/relations_hyperlink.py @@ -0,0 +1,358 @@ +from django.db import models +from django.test import TestCase +from rest_framework import serializers +from rest_framework.compat import patterns, url + + +def dummy_view(request, pk): + pass + +urlpatterns = patterns('', + url(r'^manytomanysource/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanysource-detail'), + url(r'^manytomanytarget/(?P<pk>[0-9]+)/$', dummy_view, name='manytomanytarget-detail'), + url(r'^foreignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeysource-detail'), + url(r'^foreignkeytarget/(?P<pk>[0-9]+)/$', dummy_view, name='foreignkeytarget-detail'), + url(r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableforeignkeysource-detail'), +) + + +# ManyToMany + +class ManyToManyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ManyToManySource(models.Model): + name = models.CharField(max_length=100) + targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') + + +class ManyToManyTargetSerializer(serializers.HyperlinkedModelSerializer): + sources = serializers.ManyHyperlinkedRelatedField(view_name='manytomanysource-detail') + + class Meta: + model = ManyToManyTarget + + +class ManyToManySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = ManyToManySource + + +# ForeignKey + +class ForeignKeyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer): + sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail', read_only=True) + + class Meta: + model = ForeignKeyTarget + + +class ForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = ForeignKeySource + + +# Nullable ForeignKey + +class NullableForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') + + +class NullableForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = NullableForeignKeySource + + +# TODO: Add test that .data cannot be accessed prior to .is_valid + +class HyperlinkedManyToManyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + for idx in range(1, 4): + target = ManyToManyTarget(name='target-%d' % idx) + target.save() + source = ManyToManySource(name='source-%d' % idx) + source.save() + for target in ManyToManyTarget.objects.all(): + source.targets.add(target) + + def test_many_to_many_retrieve(self): + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_retrieve(self): + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_update(self): + data = {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + instance = ManyToManySource.objects.get(pk=1) + serializer = ManyToManySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_update(self): + data = {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']} + instance = ManyToManyTarget.objects.get(pk=1) + serializer = ManyToManyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 1 is updated, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']} + + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_create(self): + data = {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} + serializer = ManyToManySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is added, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'url': '/manytomanysource/1/', 'name': u'source-1', 'targets': ['/manytomanytarget/1/']}, + {'url': '/manytomanysource/2/', 'name': u'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']}, + {'url': '/manytomanysource/3/', 'name': u'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}, + {'url': '/manytomanysource/4/', 'name': u'source-4', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/3/']} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_create(self): + data = {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} + serializer = ManyToManyTargetSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'target-4') + + # Ensure target 4 is added, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'url': '/manytomanytarget/1/', 'name': u'target-1', 'sources': ['/manytomanysource/1/', '/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/2/', 'name': u'target-2', 'sources': ['/manytomanysource/2/', '/manytomanysource/3/']}, + {'url': '/manytomanytarget/3/', 'name': u'target-3', 'sources': ['/manytomanysource/3/']}, + {'url': '/manytomanytarget/4/', 'name': u'target-4', 'sources': ['/manytomanysource/1/', '/manytomanysource/3/']} + ] + self.assertEquals(serializer.data, expected) + + +class HyperlinkedForeignKeyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + new_target = ForeignKeyTarget(name='target-2') + new_target.save() + for idx in range(1, 4): + source = ForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_retrieve(self): + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_foreign_key_retrieve(self): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']}, + {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update(self): + data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/2/'}, + {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_invalid_null(self): + data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': None} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) + + +class HyperlinkedNullableForeignKeyTests(TestCase): + urls = 'rest_framework.tests.hyperlink_relations' + + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + for idx in range(1, 4): + source = NullableForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_create_with_valid_null(self): + data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_create_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': ''} + expected_data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, expected_data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_null(self): + data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': ''} + expected_data = {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, expected_data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + ] + self.assertEquals(serializer.data, expected) + + # reverse foreign keys MUST be read_only + # In the general case they do not provide .remove() or .clear() + # and cannot be arbitrarily set. + + # def test_reverse_foreign_key_update(self): + # data = {'id': 1, 'name': u'target-1', 'sources': [1]} + # instance = ForeignKeyTarget.objects.get(pk=1) + # serializer = ForeignKeyTargetSerializer(instance, data=data) + # self.assertTrue(serializer.is_valid()) + # self.assertEquals(serializer.data, data) + # serializer.save() + + # # Ensure target 1 is updated, and everything else is as expected + # queryset = ForeignKeyTarget.objects.all() + # serializer = ForeignKeyTargetSerializer(queryset) + # expected = [ + # {'id': 1, 'name': u'target-1', 'sources': [1]}, + # {'id': 2, 'name': u'target-2', 'sources': []}, + # ] + # self.assertEquals(serializer.data, expected) diff --git a/rest_framework/tests/relations_nested.py b/rest_framework/tests/relations_nested.py new file mode 100644 index 00000000..0d18d4ad --- /dev/null +++ b/rest_framework/tests/relations_nested.py @@ -0,0 +1,52 @@ +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +# ForeignKey + +class ForeignKeyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +class ForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + model = ForeignKeySource + + +class ForeignKeyTargetSerializer(serializers.ModelSerializer): + sources = ForeignKeySourceSerializer() + + class Meta: + model = ForeignKeyTarget + + +class ReverseForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + new_target = ForeignKeyTarget(name='target-2') + new_target.save() + for idx in range(1, 4): + source = ForeignKeySource(name='source-%d' % idx, target=target) + source.save() + self.target_data = {'id': 1, 'name': u'target-1', 'sources': [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + ]} + self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} + self.data = [self.target_data, self.new_target_data] + + def check_serialized_targets(self, data): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + self.assertEquals(serializer.data, data) + + def test_reverse_foreign_key_retrieve(self): + self.check_serialized_targets(self.data) diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py new file mode 100644 index 00000000..e3360939 --- /dev/null +++ b/rest_framework/tests/relations_pk.py @@ -0,0 +1,338 @@ +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +# ManyToMany + +class ManyToManyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ManyToManySource(models.Model): + name = models.CharField(max_length=100) + targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') + + +class ManyToManyTargetSerializer(serializers.ModelSerializer): + sources = serializers.ManyPrimaryKeyRelatedField() + + class Meta: + model = ManyToManyTarget + + +class ManyToManySourceSerializer(serializers.ModelSerializer): + class Meta: + model = ManyToManySource + + +# ForeignKey + +class ForeignKeyTarget(models.Model): + name = models.CharField(max_length=100) + + +class ForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +class ForeignKeyTargetSerializer(serializers.ModelSerializer): + sources = serializers.ManyPrimaryKeyRelatedField(read_only=True) + + class Meta: + model = ForeignKeyTarget + + +class ForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + model = ForeignKeySource + + +# Nullable ForeignKey + +class NullableForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') + + +class NullableForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + model = NullableForeignKeySource + + +# TODO: Add test that .data cannot be accessed prior to .is_valid + +class PKManyToManyTests(TestCase): + def setUp(self): + for idx in range(1, 4): + target = ManyToManyTarget(name='target-%d' % idx) + target.save() + source = ManyToManySource(name='source-%d' % idx) + source.save() + for target in ManyToManyTarget.objects.all(): + source.targets.add(target) + + def test_many_to_many_retrieve(self): + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'targets': [1]}, + {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, + {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_retrieve(self): + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, + {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, + {'id': 3, 'name': u'target-3', 'sources': [3]} + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_update(self): + data = {'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]} + instance = ManyToManySource.objects.get(pk=1) + serializer = ManyToManySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]}, + {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, + {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_update(self): + data = {'id': 1, 'name': u'target-1', 'sources': [1]} + instance = ManyToManyTarget.objects.get(pk=1) + serializer = ManyToManyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 1 is updated, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [1]}, + {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, + {'id': 3, 'name': u'target-3', 'sources': [3]} + ] + self.assertEquals(serializer.data, expected) + + def test_many_to_many_create(self): + data = {'id': 4, 'name': u'source-4', 'targets': [1, 3]} + serializer = ManyToManySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is added, and everything else is as expected + queryset = ManyToManySource.objects.all() + serializer = ManyToManySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'targets': [1]}, + {'id': 2, 'name': u'source-2', 'targets': [1, 2]}, + {'id': 3, 'name': u'source-3', 'targets': [1, 2, 3]}, + {'id': 4, 'name': u'source-4', 'targets': [1, 3]}, + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_many_to_many_create(self): + data = {'id': 4, 'name': u'target-4', 'sources': [1, 3]} + serializer = ManyToManyTargetSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'target-4') + + # Ensure target 4 is added, and everything else is as expected + queryset = ManyToManyTarget.objects.all() + serializer = ManyToManyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, + {'id': 2, 'name': u'target-2', 'sources': [2, 3]}, + {'id': 3, 'name': u'target-3', 'sources': [3]}, + {'id': 4, 'name': u'target-4', 'sources': [1, 3]} + ] + self.assertEquals(serializer.data, expected) + + +class PKForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + new_target = ForeignKeyTarget(name='target-2') + new_target.save() + for idx in range(1, 4): + source = ForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_retrieve(self): + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + + def test_reverse_foreign_key_retrieve(self): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, + {'id': 2, 'name': u'target-2', 'sources': []}, + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update(self): + data = {'id': 1, 'name': u'source-1', 'target': 2} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 2}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_invalid_null(self): + data = {'id': 1, 'name': u'source-1', 'target': None} + instance = ForeignKeySource.objects.get(pk=1) + serializer = ForeignKeySourceSerializer(instance, data=data) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'target': [u'Value may not be null']}) + + +class PKNullableForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + for idx in range(1, 4): + source = NullableForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_create_with_valid_null(self): + data = {'id': 4, 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 4, 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_create_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'id': 4, 'name': u'source-4', 'target': ''} + expected_data = {'id': 4, 'name': u'source-4', 'target': None} + serializer = NullableForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, expected_data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 4 is created, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 4, 'name': u'source-4', 'target': None} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_null(self): + data = {'id': 1, 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': None}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + + def test_foreign_key_update_with_valid_emptystring(self): + """ + The emptystring should be interpreted as null in the context + of relationships. + """ + data = {'id': 1, 'name': u'source-1', 'target': ''} + expected_data = {'id': 1, 'name': u'source-1', 'target': None} + instance = NullableForeignKeySource.objects.get(pk=1) + serializer = NullableForeignKeySourceSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, expected_data) + serializer.save() + + # Ensure source 1 is updated, and everything else is as expected + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': None}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1} + ] + self.assertEquals(serializer.data, expected) + + # reverse foreign keys MUST be read_only + # In the general case they do not provide .remove() or .clear() + # and cannot be arbitrarily set. + + # def test_reverse_foreign_key_update(self): + # data = {'id': 1, 'name': u'target-1', 'sources': [1]} + # instance = ForeignKeyTarget.objects.get(pk=1) + # serializer = ForeignKeyTargetSerializer(instance, data=data) + # self.assertTrue(serializer.is_valid()) + # self.assertEquals(serializer.data, data) + # serializer.save() + + # # Ensure target 1 is updated, and everything else is as expected + # queryset = ForeignKeyTarget.objects.all() + # serializer = ForeignKeyTargetSerializer(queryset) + # expected = [ + # {'id': 1, 'name': u'target-1', 'sources': [1]}, + # {'id': 2, 'name': u'target-2', 'sources': []}, + # ] + # self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From 37acea52406edcb1c14f52360c8262ad992b8e4a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 21 Dec 2012 09:15:08 +0000 Subject: Fix up test url model now filename has changed --- rest_framework/tests/relations_hyperlink.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 9e8ecf70..53ce0074 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -78,7 +78,7 @@ class NullableForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer) # TODO: Add test that .data cannot be accessed prior to .is_valid class HyperlinkedManyToManyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' + urls = 'rest_framework.tests.relations_hyperlink' def setUp(self): for idx in range(1, 4): @@ -186,7 +186,7 @@ class HyperlinkedManyToManyTests(TestCase): class HyperlinkedForeignKeyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' + urls = 'rest_framework.tests.relations_hyperlink' def setUp(self): target = ForeignKeyTarget(name='target-1') @@ -243,7 +243,7 @@ class HyperlinkedForeignKeyTests(TestCase): class HyperlinkedNullableForeignKeyTests(TestCase): - urls = 'rest_framework.tests.hyperlink_relations' + urls = 'rest_framework.tests.relations_hyperlink' def setUp(self): target = ForeignKeyTarget(name='target-1') -- cgit v1.2.3 From 04119245ec5dc80f7376e319e5876b9fb6711c45 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 21 Dec 2012 09:15:28 +0000 Subject: Make nested tests consistent with pk and hyperlink tests --- rest_framework/tests/relations_nested.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_nested.py b/rest_framework/tests/relations_nested.py index 0d18d4ad..3482c252 100644 --- a/rest_framework/tests/relations_nested.py +++ b/rest_framework/tests/relations_nested.py @@ -35,18 +35,17 @@ class ReverseForeignKeyTests(TestCase): for idx in range(1, 4): source = ForeignKeySource(name='source-%d' % idx, target=target) source.save() - self.target_data = {'id': 1, 'name': u'target-1', 'sources': [ + + def test_reverse_foreign_key_retrieve(self): + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [ {'id': 1, 'name': u'source-1', 'target': 1}, {'id': 2, 'name': u'source-2', 'target': 1}, {'id': 3, 'name': u'source-3', 'target': 1}, + ]}, + {'id': 2, 'name': u'target-2', 'sources': [ ]} - self.new_target_data = {'id': 2, 'name': u'target-2', 'sources': []} - self.data = [self.target_data, self.new_target_data] - - def check_serialized_targets(self, data): - queryset = ForeignKeyTarget.objects.all() - serializer = ForeignKeyTargetSerializer(queryset) - self.assertEquals(serializer.data, data) - - def test_reverse_foreign_key_retrieve(self): - self.check_serialized_targets(self.data) + ] + self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From 36e1987f598a5a21a788e931c1ecb13e4c0d0ad8 Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Tue, 25 Dec 2012 18:50:00 +0200 Subject: Regression test for #532 - values overriden by "default" setting --- rest_framework/tests/models.py | 1 + rest_framework/tests/serializer.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 0759650a..ae8e42b8 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -71,6 +71,7 @@ class SlugBasedModel(RESTFrameworkModel): class DefaultValueModel(RESTFrameworkModel): text = models.CharField(default='foobar', max_length=100) + extra = models.CharField(blank=True, null=True, max_length=100) class CallableDefaultValueModel(RESTFrameworkModel): diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index f780e811..aac1f68a 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -340,7 +340,6 @@ class ModelValidationTests(TestCase): self.assertTrue(photo_serializer.save()) - class RegexValidationTest(TestCase): def test_create_failed(self): serializer = BookSerializer(data={'isbn': '1234567890'}) @@ -551,6 +550,21 @@ class DefaultValueTests(TestCase): self.assertEquals(instance.pk, 1) self.assertEquals(instance.text, 'overridden') + def test_partial_update_default(self): + """ Regression test for issue #532 """ + data = {'text': 'overridden'} + serializer = self.serializer_class(data=data, partial=True) + self.assertEquals(serializer.is_valid(), True) + instance = serializer.save() + + data = {'extra': 'extra_value'} + serializer = self.serializer_class(instance=instance, data=data, partial=True) + self.assertEquals(serializer.is_valid(), True) + instance = serializer.save() + + self.assertEquals(instance.extra, 'extra_value') + self.assertEquals(instance.text, 'overridden') + class CallableDefaultValueTests(TestCase): def setUp(self): -- cgit v1.2.3 From eefd5b05fbd7639fa813728bde44f1614875866e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 27 Dec 2012 20:20:01 +0000 Subject: Use compat import of urlpatterns --- rest_framework/tests/modelviews.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/modelviews.py b/rest_framework/tests/modelviews.py index 1f8468e8..f12e3b97 100644 --- a/rest_framework/tests/modelviews.py +++ b/rest_framework/tests/modelviews.py @@ -1,4 +1,4 @@ -# from django.conf.urls.defaults import patterns, url +# from rest_framework.compat import patterns, url # from django.forms import ModelForm # from django.contrib.auth.models import Group, User # from rest_framework.resources import ModelResource -- cgit v1.2.3 From 250a7231d3b5e44bc5ff984ef9fd515bfd238a25 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 13:10:43 +0000 Subject: Add tests for nested FKs --- rest_framework/tests/relations_nested.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_nested.py b/rest_framework/tests/relations_nested.py index 3482c252..297538c4 100644 --- a/rest_framework/tests/relations_nested.py +++ b/rest_framework/tests/relations_nested.py @@ -15,12 +15,18 @@ class ForeignKeySource(models.Model): class ForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + depth = 1 + model = ForeignKeySource + + +class FlatForeignKeySourceSerializer(serializers.ModelSerializer): class Meta: model = ForeignKeySource class ForeignKeyTargetSerializer(serializers.ModelSerializer): - sources = ForeignKeySourceSerializer() + sources = FlatForeignKeySourceSerializer() class Meta: model = ForeignKeyTarget @@ -36,6 +42,16 @@ class ReverseForeignKeyTests(TestCase): source = ForeignKeySource(name='source-%d' % idx, target=target) source.save() + def test_foreign_key_retrieve(self): + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': {'id': 1, 'name': u'target-1'}}, + {'id': 2, 'name': u'source-2', 'target': {'id': 1, 'name': u'target-1'}}, + {'id': 3, 'name': u'source-3', 'target': {'id': 1, 'name': u'target-1'}}, + ] + self.assertEquals(serializer.data, expected) + def test_reverse_foreign_key_retrieve(self): queryset = ForeignKeyTarget.objects.all() serializer = ForeignKeyTargetSerializer(queryset) -- cgit v1.2.3 From 923f81d26971510c12cb08e3061c7b37c0c6ffe8 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 13:19:05 +0000 Subject: Nested serializers now support nullable relationships, plus test. Fixes #384 --- rest_framework/tests/relations_nested.py | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_nested.py b/rest_framework/tests/relations_nested.py index 297538c4..b1147378 100644 --- a/rest_framework/tests/relations_nested.py +++ b/rest_framework/tests/relations_nested.py @@ -32,6 +32,20 @@ class ForeignKeyTargetSerializer(serializers.ModelSerializer): model = ForeignKeyTarget +# Nullable ForeignKey + +class NullableForeignKeySource(models.Model): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') + + +class NullableForeignKeySourceSerializer(serializers.ModelSerializer): + class Meta: + depth = 1 + model = NullableForeignKeySource + + class ReverseForeignKeyTests(TestCase): def setUp(self): target = ForeignKeyTarget(name='target-1') @@ -65,3 +79,24 @@ class ReverseForeignKeyTests(TestCase): ]} ] self.assertEquals(serializer.data, expected) + + +class NestedNullableForeignKeyTests(TestCase): + def setUp(self): + target = ForeignKeyTarget(name='target-1') + target.save() + for idx in range(1, 4): + if idx == 3: + target = None + source = NullableForeignKeySource(name='source-%d' % idx, target=target) + source.save() + + def test_foreign_key_retrieve_with_null(self): + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': {'id': 1, 'name': u'target-1'}}, + {'id': 2, 'name': u'source-2', 'target': {'id': 1, 'name': u'target-1'}}, + {'id': 3, 'name': u'source-3', 'target': None}, + ] + self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From bf69205cd33fc1601e5ae3c0c48ffcff1a62470b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 13:32:49 +0000 Subject: Tests for retrieving nullable relations --- rest_framework/tests/relations_hyperlink.py | 20 ++++++++++++++++---- rest_framework/tests/relations_pk.py | 20 ++++++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 53ce0074..86d7b1c2 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -249,9 +249,21 @@ class HyperlinkedNullableForeignKeyTests(TestCase): target = ForeignKeyTarget(name='target-1') target.save() for idx in range(1, 4): + if idx == 3: + target = None source = NullableForeignKeySource(name='source-%d' % idx, target=target) source.save() + def test_foreign_key_retrieve_with_null(self): + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': None}, + ] + self.assertEquals(serializer.data, expected) + def test_foreign_key_create_with_valid_null(self): data = {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} serializer = NullableForeignKeySourceSerializer(data=data) @@ -266,7 +278,7 @@ class HyperlinkedNullableForeignKeyTests(TestCase): expected = [ {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': None}, {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} ] self.assertEquals(serializer.data, expected) @@ -290,7 +302,7 @@ class HyperlinkedNullableForeignKeyTests(TestCase): expected = [ {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': None}, {'url': '/nullableforeignkeysource/4/', 'name': u'source-4', 'target': None} ] self.assertEquals(serializer.data, expected) @@ -309,7 +321,7 @@ class HyperlinkedNullableForeignKeyTests(TestCase): expected = [ {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': None}, ] self.assertEquals(serializer.data, expected) @@ -332,7 +344,7 @@ class HyperlinkedNullableForeignKeyTests(TestCase): expected = [ {'url': '/nullableforeignkeysource/1/', 'name': u'source-1', 'target': None}, {'url': '/nullableforeignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, - {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/nullableforeignkeysource/3/', 'name': u'source-3', 'target': None}, ] self.assertEquals(serializer.data, expected) diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index e3360939..7a1fe07c 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -229,9 +229,21 @@ class PKNullableForeignKeyTests(TestCase): target = ForeignKeyTarget(name='target-1') target.save() for idx in range(1, 4): + if idx == 3: + target = None source = NullableForeignKeySource(name='source-%d' % idx, target=target) source.save() + def test_foreign_key_retrieve_with_null(self): + queryset = NullableForeignKeySource.objects.all() + serializer = NullableForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': None}, + ] + self.assertEquals(serializer.data, expected) + def test_foreign_key_create_with_valid_null(self): data = {'id': 4, 'name': u'source-4', 'target': None} serializer = NullableForeignKeySourceSerializer(data=data) @@ -246,7 +258,7 @@ class PKNullableForeignKeyTests(TestCase): expected = [ {'id': 1, 'name': u'source-1', 'target': 1}, {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': None}, {'id': 4, 'name': u'source-4', 'target': None} ] self.assertEquals(serializer.data, expected) @@ -270,7 +282,7 @@ class PKNullableForeignKeyTests(TestCase): expected = [ {'id': 1, 'name': u'source-1', 'target': 1}, {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': None}, {'id': 4, 'name': u'source-4', 'target': None} ] self.assertEquals(serializer.data, expected) @@ -289,7 +301,7 @@ class PKNullableForeignKeyTests(TestCase): expected = [ {'id': 1, 'name': u'source-1', 'target': None}, {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} + {'id': 3, 'name': u'source-3', 'target': None} ] self.assertEquals(serializer.data, expected) @@ -312,7 +324,7 @@ class PKNullableForeignKeyTests(TestCase): expected = [ {'id': 1, 'name': u'source-1', 'target': None}, {'id': 2, 'name': u'source-2', 'target': 1}, - {'id': 3, 'name': u'source-3', 'target': 1} + {'id': 3, 'name': u'source-3', 'target': None} ] self.assertEquals(serializer.data, expected) -- cgit v1.2.3 From 51e2664491577cc218dfa0643e0c20532b3eb96e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 15:51:32 +0000 Subject: Add FK create tests --- rest_framework/tests/relations_pk.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index 7a1fe07c..e5391f1b 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -216,6 +216,44 @@ class PKForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_foreign_key_create(self): + data = {'id': 4, 'name': u'source-4', 'target': 2} + serializer = ForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 1 is updated, and everything else is as expected + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'id': 1, 'name': u'source-1', 'target': 1}, + {'id': 2, 'name': u'source-2', 'target': 1}, + {'id': 3, 'name': u'source-3', 'target': 1}, + {'id': 4, 'name': u'source-4', 'target': 2}, + ] + self.assertEquals(serializer.data, expected) + + # TODO: See #511 + # def test_reverse_foreign_key_create(self): + # data = {'id': 3, 'name': u'target-3', 'sources': [1, 3]} + # serializer = ForeignKeyTargetSerializer(data=data) + # self.assertTrue(serializer.is_valid()) + # obj = serializer.save() + # self.assertEquals(serializer.data, data) + # self.assertEqual(obj.name, u'target-3') + + # # Ensure target 4 is added, and everything else is as expected + # queryset = ForeignKeyTarget.objects.all() + # serializer = ForeignKeyTargetSerializer(queryset) + # expected = [ + # {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, + # {'id': 2, 'name': u'target-2', 'sources': []}, + # {'id': 3, 'name': u'target-3', 'sources': [1, 3]}, + # ] + # self.assertEquals(serializer.data, expected) + def test_foreign_key_update_with_invalid_null(self): data = {'id': 1, 'name': u'source-1', 'target': None} instance = ForeignKeySource.objects.get(pk=1) -- cgit v1.2.3 From 031a656667b1563516fa3cdb664da61243bbe00d Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 17:12:07 +0000 Subject: Added hyperlinked FK create test --- rest_framework/tests/relations_hyperlink.py | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 86d7b1c2..721e975c 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -234,6 +234,43 @@ class HyperlinkedForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_foreign_key_create(self): + data = {'url': '/foreignkeysource/4/', 'name': u'source-4', 'target': '/foreignkeytarget/2/'} + serializer = ForeignKeySourceSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'source-4') + + # Ensure source 1 is updated, and everything else is as expected + queryset = ForeignKeySource.objects.all() + serializer = ForeignKeySourceSerializer(queryset) + expected = [ + {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/2/', 'name': u'source-2', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/3/', 'name': u'source-3', 'target': '/foreignkeytarget/1/'}, + {'url': '/foreignkeysource/4/', 'name': u'source-4', 'target': '/foreignkeytarget/2/'}, + ] + self.assertEquals(serializer.data, expected) + + # def test_reverse_foreign_key_create(self): + # data = {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} + # serializer = ForeignKeyTargetSerializer(data=data) + # self.assertTrue(serializer.is_valid()) + # obj = serializer.save() + # self.assertEquals(serializer.data, data) + # self.assertEqual(obj.name, u'target-3') + + # # Ensure target 4 is added, and everything else is as expected + # queryset = ForeignKeyTarget.objects.all() + # serializer = ForeignKeyTargetSerializer(queryset) + # expected = [ + # {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/2/']}, + # {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, + # {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']}, + # ] + # self.assertEquals(serializer.data, expected) + def test_foreign_key_update_with_invalid_null(self): data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': None} instance = ForeignKeySource.objects.get(pk=1) -- cgit v1.2.3 From 0176fab4758163476d5a12f8343043b4e7d325f4 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 17:12:40 +0000 Subject: Add TODO --- rest_framework/tests/relations_hyperlink.py | 1 + 1 file changed, 1 insertion(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 721e975c..5eeabddb 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -253,6 +253,7 @@ class HyperlinkedForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + # TODO: Check this - is this a bug or is the test incorrect? # def test_reverse_foreign_key_create(self): # data = {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} # serializer = ForeignKeyTargetSerializer(data=data) -- cgit v1.2.3 From 18590a1568aa8720c5114dbf40c6f69bcb753aaf Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 18:17:48 +0000 Subject: Add test for hyperlinked reverse FK create. Refs #511 --- rest_framework/tests/relations_hyperlink.py | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 5eeabddb..f1de4c92 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -51,7 +51,7 @@ class ForeignKeySource(models.Model): class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer): - sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail', read_only=True) + sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail') class Meta: model = ForeignKeyTarget @@ -253,24 +253,23 @@ class HyperlinkedForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) - # TODO: Check this - is this a bug or is the test incorrect? - # def test_reverse_foreign_key_create(self): - # data = {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} - # serializer = ForeignKeyTargetSerializer(data=data) - # self.assertTrue(serializer.is_valid()) - # obj = serializer.save() - # self.assertEquals(serializer.data, data) - # self.assertEqual(obj.name, u'target-3') + def test_reverse_foreign_key_create(self): + data = {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} + serializer = ForeignKeyTargetSerializer(data=data) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEquals(serializer.data, data) + self.assertEqual(obj.name, u'target-3') - # # Ensure target 4 is added, and everything else is as expected - # queryset = ForeignKeyTarget.objects.all() - # serializer = ForeignKeyTargetSerializer(queryset) - # expected = [ - # {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/2/']}, - # {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, - # {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']}, - # ] - # self.assertEquals(serializer.data, expected) + # Ensure target 4 is added, and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/2/']}, + {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, + {'url': '/foreignkeytarget/3/', 'name': u'target-3', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']}, + ] + self.assertEquals(serializer.data, expected) def test_foreign_key_update_with_invalid_null(self): data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': None} -- cgit v1.2.3 From 12c4f1ecf7dd7b0e6ead5a42c0fd5cab5aa7ad27 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 29 Dec 2012 18:26:47 +0000 Subject: Add reverse FK update tests --- rest_framework/tests/relations_hyperlink.py | 17 +++++++++++++++++ rest_framework/tests/relations_pk.py | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index f1de4c92..24039410 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -234,6 +234,23 @@ class HyperlinkedForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_reverse_foreign_key_update(self): + data = {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} + instance = ForeignKeyTarget.objects.get(pk=2) + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 2 is update, and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/2/']}, + {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']}, + ] + self.assertEquals(serializer.data, expected) + def test_foreign_key_create(self): data = {'url': '/foreignkeysource/4/', 'name': u'source-4', 'target': '/foreignkeytarget/2/'} serializer = ForeignKeySourceSerializer(data=data) diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index c2e61279..01109ef9 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -216,6 +216,23 @@ class PKForeignKeyTests(TestCase): ] self.assertEquals(serializer.data, expected) + def test_reverse_foreign_key_update(self): + data = {'id': 2, 'name': u'target-2', 'sources': [1, 3]} + instance = ForeignKeyTarget.objects.get(pk=2) + serializer = ForeignKeyTargetSerializer(instance, data=data) + self.assertTrue(serializer.is_valid()) + self.assertEquals(serializer.data, data) + serializer.save() + + # Ensure target 2 is update, and everything else is as expected + queryset = ForeignKeyTarget.objects.all() + serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [2]}, + {'id': 2, 'name': u'target-2', 'sources': [1, 3]}, + ] + self.assertEquals(serializer.data, expected) + def test_foreign_key_create(self): data = {'id': 4, 'name': u'source-4', 'target': 2} serializer = ForeignKeySourceSerializer(data=data) -- cgit v1.2.3 From df1880185c87733a82a41392898e67fe02c769aa Mon Sep 17 00:00:00 2001 From: Andrew Hankinson Date: Sun, 30 Dec 2012 13:57:43 -0400 Subject: Renaming DRFRequestFactory to RequestFactory Updated tests to reflect the new name. --- rest_framework/tests/decorators.py | 5 ++--- rest_framework/tests/generics.py | 6 +++--- rest_framework/tests/utils.py | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/decorators.py b/rest_framework/tests/decorators.py index c2387f58..5e6bce4e 100644 --- a/rest_framework/tests/decorators.py +++ b/rest_framework/tests/decorators.py @@ -1,7 +1,6 @@ from django.test import TestCase from rest_framework import status from rest_framework.response import Response -# from django.test.client import RequestFactory from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from rest_framework.authentication import BasicAuthentication @@ -17,13 +16,13 @@ from rest_framework.decorators import ( permission_classes, ) -from rest_framework.tests.utils import DRFRequestFactory +from rest_framework.tests.utils import RequestFactory class DecoratorTestCase(TestCase): def setUp(self): - self.factory = DRFRequestFactory() + self.factory = RequestFactory() def _finalize_response(self, request, response, *args, **kwargs): response.request = request diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index a5432d11..33ac4b32 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -1,11 +1,11 @@ from django.test import TestCase from django.utils import simplejson as json from rest_framework import generics, serializers, status -from rest_framework.tests.utils import DRFRequestFactory +from rest_framework.tests.utils import RequestFactory from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel -factory = DRFRequestFactory() +factory = RequestFactory() class RootView(generics.ListCreateAPIView): @@ -15,7 +15,7 @@ class RootView(generics.ListCreateAPIView): model = BasicModel -class InstanceView(generics.RetrievePartialUpdateDestroyAPIView): +class InstanceView(generics.RetrieveUpdateDestroyAPIView): """ Example description for OPTIONS. """ diff --git a/rest_framework/tests/utils.py b/rest_framework/tests/utils.py index d7f14156..3906adb9 100644 --- a/rest_framework/tests/utils.py +++ b/rest_framework/tests/utils.py @@ -3,10 +3,10 @@ from django.test.client import MULTIPART_CONTENT from urlparse import urlparse -class DRFRequestFactory(RequestFactory): +class RequestFactory(RequestFactory): def __init__(self, **defaults): - super(DRFRequestFactory, self).__init__(**defaults) + super(RequestFactory, self).__init__(**defaults) def patch(self, path, data={}, content_type=MULTIPART_CONTENT, **extra): -- cgit v1.2.3 From a617a3758f635bf1ebe3464555e397d09f4dfc6d Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Mon, 31 Dec 2012 14:33:24 +0100 Subject: Don't persist relation changes in ModelSerializer#restore_object() --- rest_framework/tests/relations_hyperlink.py | 6 +++--- rest_framework/tests/relations_pk.py | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 24039410..4179ec68 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -114,8 +114,8 @@ class HyperlinkedManyToManyTests(TestCase): instance = ManyToManySource.objects.get(pk=1) serializer = ManyToManySourceSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() + self.assertEquals(serializer.data, data) # Ensure source 1 is updated, and everything else is as expected queryset = ManyToManySource.objects.all() @@ -132,8 +132,8 @@ class HyperlinkedManyToManyTests(TestCase): instance = ManyToManyTarget.objects.get(pk=1) serializer = ManyToManyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() + self.assertEquals(serializer.data, data) # Ensure target 1 is updated, and everything else is as expected queryset = ManyToManyTarget.objects.all() @@ -239,8 +239,8 @@ class HyperlinkedForeignKeyTests(TestCase): instance = ForeignKeyTarget.objects.get(pk=2) serializer = ForeignKeyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() + self.assertEquals(serializer.data, data) # Ensure target 2 is update, and everything else is as expected queryset = ForeignKeyTarget.objects.all() diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index 01109ef9..28967099 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -99,8 +99,8 @@ class PKManyToManyTests(TestCase): instance = ManyToManySource.objects.get(pk=1) serializer = ManyToManySourceSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() + self.assertEquals(serializer.data, data) # Ensure source 1 is updated, and everything else is as expected queryset = ManyToManySource.objects.all() @@ -117,8 +117,8 @@ class PKManyToManyTests(TestCase): instance = ManyToManyTarget.objects.get(pk=1) serializer = ManyToManyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) serializer.save() + self.assertEquals(serializer.data, data) # Ensure target 1 is updated, and everything else is as expected queryset = ManyToManyTarget.objects.all() @@ -221,8 +221,18 @@ class PKForeignKeyTests(TestCase): instance = ForeignKeyTarget.objects.get(pk=2) serializer = ForeignKeyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) - self.assertEquals(serializer.data, data) + # We shouldn't have saved anything to the db yet since save + # hasn't been called. + queryset = ForeignKeyTarget.objects.all() + new_serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]}, + {'id': 2, 'name': u'target-2', 'sources': []}, + ] + self.assertEquals(new_serializer.data, expected) + serializer.save() + self.assertEquals(serializer.data, data) # Ensure target 2 is update, and everything else is as expected queryset = ForeignKeyTarget.objects.all() @@ -241,7 +251,7 @@ class PKForeignKeyTests(TestCase): self.assertEquals(serializer.data, data) self.assertEqual(obj.name, u'source-4') - # Ensure source 1 is updated, and everything else is as expected + # Ensure source 4 is added, and everything else is as expected queryset = ForeignKeySource.objects.all() serializer = ForeignKeySourceSerializer(queryset) expected = [ @@ -260,7 +270,7 @@ class PKForeignKeyTests(TestCase): self.assertEquals(serializer.data, data) self.assertEqual(obj.name, u'target-3') - # Ensure target 4 is added, and everything else is as expected + # Ensure target 3 is added, and everything else is as expected queryset = ForeignKeyTarget.objects.all() serializer = ForeignKeyTargetSerializer(queryset) expected = [ -- cgit v1.2.3 From 44771e81b23ca8ef982e4bb0d0ac5a435b684b22 Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Tue, 1 Jan 2013 17:51:39 +0100 Subject: Update HyperlinkedForeignKeyTests to match PKForeignKeyTests --- rest_framework/tests/relations_hyperlink.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 4179ec68..0a7ea0f4 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -239,6 +239,16 @@ class HyperlinkedForeignKeyTests(TestCase): instance = ForeignKeyTarget.objects.get(pk=2) serializer = ForeignKeyTargetSerializer(instance, data=data) self.assertTrue(serializer.is_valid()) + # We shouldn't have saved anything to the db yet since save + # hasn't been called. + queryset = ForeignKeyTarget.objects.all() + new_serializer = ForeignKeyTargetSerializer(queryset) + expected = [ + {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']}, + {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, + ] + self.assertEquals(new_serializer.data, expected) + serializer.save() self.assertEquals(serializer.data, data) -- cgit v1.2.3 From 1c8fccfdcd6186023a6ca6c8d50759172081d05a Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Wed, 2 Jan 2013 22:07:23 +0200 Subject: Regression test for #542 --- rest_framework/tests/files.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/files.py b/rest_framework/tests/files.py index 5dd57b7c..a98e33ef 100644 --- a/rest_framework/tests/files.py +++ b/rest_framework/tests/files.py @@ -25,7 +25,6 @@ class UploadedFileSerializer(serializers.Serializer): class FileSerializerTests(TestCase): - def test_create(self): now = datetime.datetime.now() file = StringIO.StringIO('stuff') @@ -37,3 +36,16 @@ class FileSerializerTests(TestCase): self.assertEquals(serializer.object.created, uploaded_file.created) self.assertEquals(serializer.object.file, uploaded_file.file) self.assertFalse(serializer.object is uploaded_file) + + def test_creation_failure(self): + """ + Passing files=None should result in an ValidationError + + Regression test for: + https://github.com/tomchristie/django-rest-framework/issues/542 + """ + now = datetime.datetime.now() + + serializer = UploadedFileSerializer(data={'created': now}, files=None) + self.assertFalse(serializer.is_valid()) + self.assertIn('file', serializer.errors) -- cgit v1.2.3 From 3f5e938247ab05efbc8e9a2a21ef1a610231a763 Mon Sep 17 00:00:00 2001 From: Yuri Prezument Date: Thu, 3 Jan 2013 08:28:17 +0200 Subject: Some cleanup --- rest_framework/tests/files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/files.py b/rest_framework/tests/files.py index a98e33ef..446e23c0 100644 --- a/rest_framework/tests/files.py +++ b/rest_framework/tests/files.py @@ -46,6 +46,6 @@ class FileSerializerTests(TestCase): """ now = datetime.datetime.now() - serializer = UploadedFileSerializer(data={'created': now}, files=None) + serializer = UploadedFileSerializer(data={'created': now}) self.assertFalse(serializer.is_valid()) self.assertIn('file', serializer.errors) -- cgit v1.2.3 From 8fd1f09dad9a5decdfd50aaeade6e5c9ba1459fc Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Thu, 3 Jan 2013 10:23:13 +0100 Subject: Move relation tests models into models.py --- rest_framework/tests/models.py | 28 ++++++++++++++++++++++++++ rest_framework/tests/relations_hyperlink.py | 25 +---------------------- rest_framework/tests/relations_nested.py | 20 +------------------ rest_framework/tests/relations_pk.py | 31 +---------------------------- 4 files changed, 31 insertions(+), 73 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index 0759650a..54fa2dec 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -176,3 +176,31 @@ class OptionalRelationModel(RESTFrameworkModel): # Model for RegexField class Book(RESTFrameworkModel): isbn = models.CharField(max_length=13) + + +# Models for relations tests +# ManyToMany +class ManyToManyTarget(RESTFrameworkModel): + name = models.CharField(max_length=100) + + +class ManyToManySource(RESTFrameworkModel): + name = models.CharField(max_length=100) + targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') + + +# ForeignKey +class ForeignKeyTarget(RESTFrameworkModel): + name = models.CharField(max_length=100) + + +class ForeignKeySource(RESTFrameworkModel): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, related_name='sources') + + +# Nullable ForeignKey +class NullableForeignKeySource(RESTFrameworkModel): + name = models.CharField(max_length=100) + target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, + related_name='nullable_sources') diff --git a/rest_framework/tests/relations_hyperlink.py b/rest_framework/tests/relations_hyperlink.py index 0a7ea0f4..a7f8a035 100644 --- a/rest_framework/tests/relations_hyperlink.py +++ b/rest_framework/tests/relations_hyperlink.py @@ -2,7 +2,7 @@ from django.db import models from django.test import TestCase from rest_framework import serializers from rest_framework.compat import patterns, url - +from rest_framework.tests.models import ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource def dummy_view(request, pk): pass @@ -15,18 +15,6 @@ urlpatterns = patterns('', url(r'^nullableforeignkeysource/(?P<pk>[0-9]+)/$', dummy_view, name='nullableforeignkeysource-detail'), ) - -# ManyToMany - -class ManyToManyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ManyToManySource(models.Model): - name = models.CharField(max_length=100) - targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') - - class ManyToManyTargetSerializer(serializers.HyperlinkedModelSerializer): sources = serializers.ManyHyperlinkedRelatedField(view_name='manytomanysource-detail') @@ -39,17 +27,6 @@ class ManyToManySourceSerializer(serializers.HyperlinkedModelSerializer): model = ManyToManySource -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') - - class ForeignKeyTargetSerializer(serializers.HyperlinkedModelSerializer): sources = serializers.ManyHyperlinkedRelatedField(view_name='foreignkeysource-detail') diff --git a/rest_framework/tests/relations_nested.py b/rest_framework/tests/relations_nested.py index b1147378..5710c1ef 100644 --- a/rest_framework/tests/relations_nested.py +++ b/rest_framework/tests/relations_nested.py @@ -1,17 +1,7 @@ from django.db import models from django.test import TestCase from rest_framework import serializers - - -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') +from rest_framework.tests.models import ForeignKeyTarget, ForeignKeySource, NullableForeignKeySource class ForeignKeySourceSerializer(serializers.ModelSerializer): @@ -32,14 +22,6 @@ class ForeignKeyTargetSerializer(serializers.ModelSerializer): model = ForeignKeyTarget -# Nullable ForeignKey - -class NullableForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, - related_name='nullable_sources') - - class NullableForeignKeySourceSerializer(serializers.ModelSerializer): class Meta: depth = 1 diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index 28967099..af6da2c0 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -1,17 +1,7 @@ from django.db import models from django.test import TestCase from rest_framework import serializers - - -# ManyToMany - -class ManyToManyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ManyToManySource(models.Model): - name = models.CharField(max_length=100) - targets = models.ManyToManyField(ManyToManyTarget, related_name='sources') +from rest_framework.tests.models import ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource, NullableForeignKeySource class ManyToManyTargetSerializer(serializers.ModelSerializer): @@ -26,17 +16,6 @@ class ManyToManySourceSerializer(serializers.ModelSerializer): model = ManyToManySource -# ForeignKey - -class ForeignKeyTarget(models.Model): - name = models.CharField(max_length=100) - - -class ForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, related_name='sources') - - class ForeignKeyTargetSerializer(serializers.ModelSerializer): sources = serializers.ManyPrimaryKeyRelatedField() @@ -49,14 +28,6 @@ class ForeignKeySourceSerializer(serializers.ModelSerializer): model = ForeignKeySource -# Nullable ForeignKey - -class NullableForeignKeySource(models.Model): - name = models.CharField(max_length=100) - target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, - related_name='nullable_sources') - - class NullableForeignKeySourceSerializer(serializers.ModelSerializer): class Meta: model = NullableForeignKeySource -- cgit v1.2.3 From 6e9865cb71ff45e90020d3d0dc7c40f20c760d2e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 3 Jan 2013 23:17:31 +0000 Subject: Fix for #446. Note: Also needs applying to other relational types. --- rest_framework/tests/fields.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 rest_framework/tests/fields.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py new file mode 100644 index 00000000..147a9229 --- /dev/null +++ b/rest_framework/tests/fields.py @@ -0,0 +1,18 @@ +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +class NullModel(models.Model): + pass + + +class FieldTests(TestCase): + def test_pk_related_field_with_empty_string(self): + """ + Regression test for #446 + + https://github.com/tomchristie/django-rest-framework/issues/446 + """ + field = serializers.PrimaryKeyRelatedField(queryset=NullModel.objects.all()) + self.assertRaises(serializers.ValidationError, field.from_native, ('',)) -- cgit v1.2.3 From 4c86fd46d772e1fd3789d9ed2a76b9b92cce0872 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 4 Jan 2013 13:05:31 +0000 Subject: Rename module for basic relational field tests --- rest_framework/tests/fields.py | 18 ------------------ rest_framework/tests/relations.py | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) delete mode 100644 rest_framework/tests/fields.py create mode 100644 rest_framework/tests/relations.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py deleted file mode 100644 index 147a9229..00000000 --- a/rest_framework/tests/fields.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.db import models -from django.test import TestCase -from rest_framework import serializers - - -class NullModel(models.Model): - pass - - -class FieldTests(TestCase): - def test_pk_related_field_with_empty_string(self): - """ - Regression test for #446 - - https://github.com/tomchristie/django-rest-framework/issues/446 - """ - field = serializers.PrimaryKeyRelatedField(queryset=NullModel.objects.all()) - self.assertRaises(serializers.ValidationError, field.from_native, ('',)) diff --git a/rest_framework/tests/relations.py b/rest_framework/tests/relations.py new file mode 100644 index 00000000..108ec473 --- /dev/null +++ b/rest_framework/tests/relations.py @@ -0,0 +1,22 @@ +""" +General tests for relational fields. +""" + +from django.db import models +from django.test import TestCase +from rest_framework import serializers + + +class NullModel(models.Model): + pass + + +class FieldTests(TestCase): + def test_pk_related_field_with_empty_string(self): + """ + Regression test for #446 + + https://github.com/tomchristie/django-rest-framework/issues/446 + """ + field = serializers.PrimaryKeyRelatedField(queryset=NullModel.objects.all()) + self.assertRaises(serializers.ValidationError, field.from_native, ('',)) -- cgit v1.2.3 From eb14278a3b08247c0aff5b2338a98203b51728c3 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 4 Jan 2013 13:50:40 +0000 Subject: Add proper validation for updating relational fields with incorrect types. Fixes #446. --- rest_framework/tests/relations.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/relations.py b/rest_framework/tests/relations.py index 108ec473..91daea8a 100644 --- a/rest_framework/tests/relations.py +++ b/rest_framework/tests/relations.py @@ -19,4 +19,15 @@ class FieldTests(TestCase): https://github.com/tomchristie/django-rest-framework/issues/446 """ field = serializers.PrimaryKeyRelatedField(queryset=NullModel.objects.all()) - self.assertRaises(serializers.ValidationError, field.from_native, ('',)) + self.assertRaises(serializers.ValidationError, field.from_native, '') + self.assertRaises(serializers.ValidationError, field.from_native, []) + + def test_hyperlinked_related_field_with_empty_string(self): + field = serializers.HyperlinkedRelatedField(queryset=NullModel.objects.all(), view_name='') + self.assertRaises(serializers.ValidationError, field.from_native, '') + self.assertRaises(serializers.ValidationError, field.from_native, []) + + def test_slug_related_field_with_empty_string(self): + field = serializers.SlugRelatedField(queryset=NullModel.objects.all(), slug_field='pk') + self.assertRaises(serializers.ValidationError, field.from_native, '') + self.assertRaises(serializers.ValidationError, field.from_native, []) -- cgit v1.2.3 From 26f9acb45ac0dcd1363399f518834c56d3f9984d Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 4 Jan 2013 14:11:05 +0000 Subject: Validation errors instead of exceptions when serializers receive incorrect types. Fixes #402. --- rest_framework/tests/serializer.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 8767385e..bd96ba23 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -69,6 +69,7 @@ class AlbumsSerializer(serializers.ModelSerializer): model = Album fields = ['title'] # lists are also valid options + class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer): class Meta: model = HasPositiveIntegerAsChoice @@ -240,6 +241,25 @@ class ValidationTests(TestCase): self.assertFalse(serializer.is_valid()) self.assertEquals(serializer.errors, {'content': [u'Test not in value']}) + def test_bad_type_data_is_false(self): + """ + Data of the wrong type is not valid. + """ + data = ['i am', 'a', 'list'] + serializer = CommentSerializer(self.comment, data=data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'non_field_errors': [u'Invalid data']}) + + data = 'and i am a string' + serializer = CommentSerializer(self.comment, data=data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'non_field_errors': [u'Invalid data']}) + + data = 42 + serializer = CommentSerializer(self.comment, data=data) + self.assertEquals(serializer.is_valid(), False) + self.assertEquals(serializer.errors, {'non_field_errors': [u'Invalid data']}) + def test_cross_field_validation(self): class CommentSerializerWithCrossFieldValidator(CommentSerializer): -- cgit v1.2.3 From a061e3d9e20c4c481c2ac2eee5b17bb1430cace6 Mon Sep 17 00:00:00 2001 From: Juan Riaza Date: Sat, 5 Jan 2013 13:40:02 +0100 Subject: deprecate simplejson --- rest_framework/tests/authentication.py | 2 +- rest_framework/tests/generics.py | 2 +- rest_framework/tests/hyperlinkedserializers.py | 2 +- rest_framework/tests/request.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 838e081b..e86041bc 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -1,7 +1,6 @@ from django.contrib.auth.models import User from django.http import HttpResponse from django.test import Client, TestCase -from django.utils import simplejson as json from rest_framework import permissions from rest_framework.authtoken.models import Token @@ -9,6 +8,7 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.compat import patterns from rest_framework.views import APIView +import json import base64 diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 843017eb..4799a04b 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -1,6 +1,6 @@ +import json from django.db import models from django.test import TestCase -from django.utils import simplejson as json from rest_framework import generics, serializers, status from rest_framework.tests.utils import RequestFactory from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel diff --git a/rest_framework/tests/hyperlinkedserializers.py b/rest_framework/tests/hyperlinkedserializers.py index ee4d8e57..c6a8224b 100644 --- a/rest_framework/tests/hyperlinkedserializers.py +++ b/rest_framework/tests/hyperlinkedserializers.py @@ -1,6 +1,6 @@ +import json from django.test import TestCase from django.test.client import RequestFactory -from django.utils import simplejson as json from rest_framework import generics, status, serializers from rest_framework.compat import patterns, url from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index 1f05ff8f..4b032405 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -1,12 +1,12 @@ """ Tests for content parsing, and form-overloaded content parsing. """ +import json from django.contrib.auth.models import User from django.contrib.auth import authenticate, login, logout from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, Client from django.test.client import RequestFactory -from django.utils import simplejson as json from rest_framework import status from rest_framework.authentication import SessionAuthentication from rest_framework.compat import patterns -- cgit v1.2.3 From c736b80290dfd650bee0fa3c530da65792dcde32 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Mon, 7 Jan 2013 12:52:20 +0000 Subject: Be more informative when reporting import errors. --- rest_framework/tests/extras/__init__.py | 0 rest_framework/tests/extras/bad_import.py | 1 + rest_framework/tests/settings.py | 21 +++++++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 rest_framework/tests/extras/__init__.py create mode 100644 rest_framework/tests/extras/bad_import.py create mode 100644 rest_framework/tests/settings.py (limited to 'rest_framework/tests') diff --git a/rest_framework/tests/extras/__init__.py b/rest_framework/tests/extras/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rest_framework/tests/extras/bad_import.py b/rest_framework/tests/extras/bad_import.py new file mode 100644 index 00000000..68263d94 --- /dev/null +++ b/rest_framework/tests/extras/bad_import.py @@ -0,0 +1 @@ +raise ValueError diff --git a/rest_framework/tests/settings.py b/rest_framework/tests/settings.py new file mode 100644 index 00000000..0293fdc3 --- /dev/null +++ b/rest_framework/tests/settings.py @@ -0,0 +1,21 @@ +"""Tests for the settings module""" +from django.test import TestCase + +from rest_framework.settings import APISettings, DEFAULTS, IMPORT_STRINGS + + +class TestSettings(TestCase): + """Tests relating to the api settings""" + + def test_non_import_errors(self): + """Make sure other errors aren't suppressed.""" + settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.tests.extras.bad_import.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS) + with self.assertRaises(ValueError): + settings.DEFAULT_MODEL_SERIALIZER_CLASS + + def test_import_error_message_maintained(self): + """Make sure real import errors are captured and raised sensibly.""" + settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.tests.extras.not_here.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS) + with self.assertRaises(ImportError) as cm: + settings.DEFAULT_MODEL_SERIALIZER_CLASS + self.assertTrue('ImportError' in str(cm.exception)) -- cgit v1.2.3