mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-26 05:31:07 +03:00 
			
		
		
		
	Merge pull request #407 from ludwigkraatz/location_header
Location header when Creating a Resource with HyperlinkedIdentityField
This commit is contained in:
		
						commit
						0cfb27b40e
					
				|  | @ -59,6 +59,7 @@ The following people have helped make REST framework great. | ||||||
| * Toni Michel - [tonimichel] | * Toni Michel - [tonimichel] | ||||||
| * Ben Konrath - [benkonrath] | * Ben Konrath - [benkonrath] | ||||||
| * Marc Aymerich - [glic3rinu] | * Marc Aymerich - [glic3rinu] | ||||||
|  | * Ludwig Kraatz - [ludwigkraatz] | ||||||
| 
 | 
 | ||||||
| Many thanks to everyone who's contributed to the project. | Many thanks to everyone who's contributed to the project. | ||||||
| 
 | 
 | ||||||
|  | @ -153,3 +154,4 @@ To contact the author directly: | ||||||
| [tonimichel]: https://github.com/tonimichel | [tonimichel]: https://github.com/tonimichel | ||||||
| [benkonrath]: https://github.com/benkonrath | [benkonrath]: https://github.com/benkonrath | ||||||
| [glic3rinu]: https://github.com/glic3rinu | [glic3rinu]: https://github.com/glic3rinu | ||||||
|  | [ludwigkraatz]: https://github.com/ludwigkraatz | ||||||
|  |  | ||||||
|  | @ -19,9 +19,16 @@ class CreateModelMixin(object): | ||||||
|         if serializer.is_valid(): |         if serializer.is_valid(): | ||||||
|             self.pre_save(serializer.object) |             self.pre_save(serializer.object) | ||||||
|             self.object = serializer.save() |             self.object = serializer.save() | ||||||
|             return Response(serializer.data, status=status.HTTP_201_CREATED) |             headers = self.get_success_headers(serializer.data) | ||||||
|  |             return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) | ||||||
|         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) |         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | ||||||
|      |      | ||||||
|  |     def get_success_headers(self, data): | ||||||
|  |         if 'url' in data: | ||||||
|  |             return {'Location': data.get('url')} | ||||||
|  |         else: | ||||||
|  |             return {} | ||||||
|  |      | ||||||
|     def pre_save(self, obj): |     def pre_save(self, obj): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,10 +20,13 @@ class Response(SimpleTemplateResponse): | ||||||
|         """ |         """ | ||||||
|         super(Response, self).__init__(None, status=status) |         super(Response, self).__init__(None, status=status) | ||||||
|         self.data = data |         self.data = data | ||||||
|         self.headers = headers and headers[:] or [] |  | ||||||
|         self.template_name = template_name |         self.template_name = template_name | ||||||
|         self.exception = exception |         self.exception = exception | ||||||
|          |          | ||||||
|  |         if headers: | ||||||
|  |             for name,value in headers.iteritems(): | ||||||
|  |                 self[name] = value | ||||||
|  | 
 | ||||||
|     @property |     @property | ||||||
|     def rendered_content(self): |     def rendered_content(self): | ||||||
|         renderer = getattr(self, 'accepted_renderer', None) |         renderer = getattr(self, 'accepted_renderer', None) | ||||||
|  |  | ||||||
|  | @ -8,12 +8,13 @@ factory = RequestFactory() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BlogPostCommentSerializer(serializers.ModelSerializer): | class BlogPostCommentSerializer(serializers.ModelSerializer): | ||||||
|  |     url = serializers.HyperlinkedIdentityField(view_name='blogpostcomment-detail') | ||||||
|     text = serializers.CharField() |     text = serializers.CharField() | ||||||
|     blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail') |     blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail') | ||||||
| 
 | 
 | ||||||
|     class Meta: |     class Meta: | ||||||
|         model = BlogPostComment |         model = BlogPostComment | ||||||
|         fields = ('text', 'blog_post_url') |         fields = ('text', 'blog_post_url', 'url') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PhotoSerializer(serializers.Serializer): | class PhotoSerializer(serializers.Serializer): | ||||||
|  | @ -53,6 +54,9 @@ class BlogPostCommentListCreate(generics.ListCreateAPIView): | ||||||
|     model = BlogPostComment |     model = BlogPostComment | ||||||
|     serializer_class = BlogPostCommentSerializer |     serializer_class = BlogPostCommentSerializer | ||||||
| 
 | 
 | ||||||
|  | class BlogPostCommentDetail(generics.RetrieveAPIView): | ||||||
|  |     model = BlogPostComment | ||||||
|  |     serializer_class = BlogPostCommentSerializer | ||||||
| 
 | 
 | ||||||
| class BlogPostDetail(generics.RetrieveAPIView): | class BlogPostDetail(generics.RetrieveAPIView): | ||||||
|     model = BlogPost |     model = BlogPost | ||||||
|  | @ -80,6 +84,7 @@ urlpatterns = patterns('', | ||||||
|     url(r'^manytomany/(?P<pk>\d+)/$', ManyToManyDetail.as_view(), name='manytomanymodel-detail'), |     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'^posts/(?P<pk>\d+)/$', BlogPostDetail.as_view(), name='blogpost-detail'), | ||||||
|     url(r'^comments/$', BlogPostCommentListCreate.as_view(), name='blogpostcomment-list'), |     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'^albums/(?P<title>\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'), |     url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'), | ||||||
|  | @ -191,6 +196,7 @@ class TestCreateWithForeignKeys(TestCase): | ||||||
|         request = factory.post('/comments/', data=data) |         request = factory.post('/comments/', data=data) | ||||||
|         response = self.create_view(request).render() |         response = self.create_view(request).render() | ||||||
|         self.assertEqual(response.status_code, status.HTTP_201_CREATED) |         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.count(), 1) | ||||||
|         self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment') |         self.assertEqual(self.post.blogpostcomment_set.all()[0].text, 'A test comment') | ||||||
| 
 | 
 | ||||||
|  | @ -215,6 +221,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase): | ||||||
|         request = factory.post('/photos/', data=data) |         request = factory.post('/photos/', data=data) | ||||||
|         response = self.list_create_view(request).render() |         response = self.list_create_view(request).render() | ||||||
|         self.assertEqual(response.status_code, status.HTTP_201_CREATED) |         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) |         self.assertEqual(self.post.photo_set.count(), 1) | ||||||
|         self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') |         self.assertEqual(self.post.photo_set.all()[0].description, 'A test photo') | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -106,7 +106,7 @@ class ThrottlingTests(TestCase): | ||||||
|             if expect is not None: |             if expect is not None: | ||||||
|                 self.assertEquals(response['X-Throttle-Wait-Seconds'], expect) |                 self.assertEquals(response['X-Throttle-Wait-Seconds'], expect) | ||||||
|             else: |             else: | ||||||
|                 self.assertFalse('X-Throttle-Wait-Seconds' in response.headers) |                 self.assertFalse('X-Throttle-Wait-Seconds' in response) | ||||||
| 
 | 
 | ||||||
|     def test_seconds_fields(self): |     def test_seconds_fields(self): | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user