From 342a940708fb2509dde9f798f57449464f306f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20R=2E=20Sede=C3=B1o?= Date: Mon, 13 Jul 2015 15:02:09 -0400 Subject: [PATCH 1/2] A test for a POST that returns multiple objects, which triggers issue #2918 --- tests/test_generics.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/test_generics.py b/tests/test_generics.py index 2e47df50fb..334988e783 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -64,6 +64,16 @@ class FKInstanceView(generics.RetrieveUpdateDestroyAPIView): serializer_class = ForeignKeySerializer +class ManyPostView(generics.GenericAPIView): + queryset = BasicModel.objects.all() + serializer_class = BasicSerializer + renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer) + + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(self.get_queryset(), many=True) + return Response(serializer.data, status.HTTP_200_OK) + + class SlugBasedInstanceView(InstanceView): """ A model with a slug-field. @@ -542,3 +552,30 @@ def get(self, request): request = factory.get('/') with pytest.raises(RuntimeError): view(request).render() + + +class TestManyPostView(TestCase): + def setUp(self): + """ + Create 3 BasicModel instances. + """ + items = ['foo', 'bar', 'baz'] + for item in items: + BasicModel(text=item).save() + self.objects = BasicModel.objects + self.data = [ + {'id': obj.id, 'text': obj.text} + for obj in self.objects.all() + ] + self.view = ManyPostView.as_view() + + def test_post_many_post_view(self): + """ + POST request to ManyPostView should return a list of objects. + """ + data = {} + request = factory.post('/', data, format='json') + with self.assertNumQueries(1): + response = self.view(request).render() + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(response.data), 3) From 8ee63e90b87989c5c22d92e3440ec3e689ca8bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20R=2E=20Sede=C3=B1o?= Date: Tue, 23 Feb 2016 13:01:46 -0500 Subject: [PATCH 2/2] Collect serialziers to try when rendering the Browsable API The first one should work, if it doesn't because of Issue #2918, then the second one should work. If no collected serializer worked, raise the exception generated by the last one. --- rest_framework/renderers.py | 54 +++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 024f0eb8ba..9740a0409f 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -473,32 +473,40 @@ def get_rendered_html_form(self, data, view, method, request): ): return + serializers = [] if existing_serializer is not None: - serializer = existing_serializer + serializers.append(existing_serializer) + + if has_serializer: + if method in ('PUT', 'PATCH'): + serializers.append(view.get_serializer(instance=instance, **kwargs)) + else: + serializers.append(view.get_serializer(**kwargs)) else: - if has_serializer: - if method in ('PUT', 'PATCH'): - serializer = view.get_serializer(instance=instance, **kwargs) - else: - serializer = view.get_serializer(**kwargs) + # at this point we must have a serializer_class + if method in ('PUT', 'PATCH'): + serializers.append(self._get_serializer(view.serializer_class, view, + request, instance=instance, **kwargs)) else: - # at this point we must have a serializer_class - if method in ('PUT', 'PATCH'): - serializer = self._get_serializer(view.serializer_class, view, - request, instance=instance, **kwargs) - else: - serializer = self._get_serializer(view.serializer_class, view, - request, **kwargs) - - if hasattr(serializer, 'initial_data'): - serializer.is_valid() - - form_renderer = self.form_renderer_class() - return form_renderer.render( - serializer.data, - self.accepted_media_type, - {'style': {'template_pack': 'rest_framework/horizontal'}} - ) + serializers.append(self._get_serializer(view.serializer_class, view, + request, **kwargs)) + + for serializer in serializers: + try: + if hasattr(serializer, 'initial_data'): + serializer.is_valid() + + form_renderer = self.form_renderer_class() + return form_renderer.render( + serializer.data, + self.accepted_media_type, + {'style': {'template_pack': 'rest_framework/horizontal'}} + ) + except TypeError: + pass + # If none of the rendering attempts succeeded, raise the TypeError generated by the last + # attempt. + raise def get_raw_data_form(self, data, view, method, request): """