mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Fixes BrowsableAPIRenderer for usage with ListSerializer. (#7530)
				
					
				
			Renders list of items in raw_data_form and does not renders form in template while using with `ListSerializer` (`many=True`).
This commit is contained in:
		
							parent
							
								
									376a5cbbba
								
							
						
					
					
						commit
						02d9bfc2dd
					
				| 
						 | 
					@ -506,6 +506,9 @@ class BrowsableAPIRenderer(BaseRenderer):
 | 
				
			||||||
            return self.render_form_for_serializer(serializer)
 | 
					            return self.render_form_for_serializer(serializer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def render_form_for_serializer(self, serializer):
 | 
					    def render_form_for_serializer(self, serializer):
 | 
				
			||||||
 | 
					        if isinstance(serializer, serializers.ListSerializer):
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if hasattr(serializer, 'initial_data'):
 | 
					        if hasattr(serializer, 'initial_data'):
 | 
				
			||||||
            serializer.is_valid()
 | 
					            serializer.is_valid()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -555,10 +558,13 @@ class BrowsableAPIRenderer(BaseRenderer):
 | 
				
			||||||
                context['indent'] = 4
 | 
					                context['indent'] = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # strip HiddenField from output
 | 
					                # strip HiddenField from output
 | 
				
			||||||
 | 
					                is_list_serializer = isinstance(serializer, serializers.ListSerializer)
 | 
				
			||||||
 | 
					                serializer = serializer.child if is_list_serializer else serializer
 | 
				
			||||||
                data = serializer.data.copy()
 | 
					                data = serializer.data.copy()
 | 
				
			||||||
                for name, field in serializer.fields.items():
 | 
					                for name, field in serializer.fields.items():
 | 
				
			||||||
                    if isinstance(field, serializers.HiddenField):
 | 
					                    if isinstance(field, serializers.HiddenField):
 | 
				
			||||||
                        data.pop(name, None)
 | 
					                        data.pop(name, None)
 | 
				
			||||||
 | 
					                data = [data] if is_list_serializer else data
 | 
				
			||||||
                content = renderer.render(data, accepted, context)
 | 
					                content = renderer.render(data, accepted, context)
 | 
				
			||||||
                # Renders returns bytes, but CharField expects a str.
 | 
					                # Renders returns bytes, but CharField expects a str.
 | 
				
			||||||
                content = content.decode()
 | 
					                content = content.decode()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -633,6 +633,9 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
 | 
				
			||||||
    class AuthExampleViewSet(ExampleViewSet):
 | 
					    class AuthExampleViewSet(ExampleViewSet):
 | 
				
			||||||
        permission_classes = [permissions.IsAuthenticated]
 | 
					        permission_classes = [permissions.IsAuthenticated]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SimpleSerializer(serializers.Serializer):
 | 
				
			||||||
 | 
					        name = serializers.CharField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    router = SimpleRouter()
 | 
					    router = SimpleRouter()
 | 
				
			||||||
    router.register('examples', ExampleViewSet, basename='example')
 | 
					    router.register('examples', ExampleViewSet, basename='example')
 | 
				
			||||||
    router.register('auth-examples', AuthExampleViewSet, basename='auth-example')
 | 
					    router.register('auth-examples', AuthExampleViewSet, basename='auth-example')
 | 
				
			||||||
| 
						 | 
					@ -640,6 +643,62 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        self.renderer = BrowsableAPIRenderer()
 | 
					        self.renderer = BrowsableAPIRenderer()
 | 
				
			||||||
 | 
					        self.renderer.accepted_media_type = ''
 | 
				
			||||||
 | 
					        self.renderer.renderer_context = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_render_form_for_serializer(self):
 | 
				
			||||||
 | 
					        with self.subTest('Serializer'):
 | 
				
			||||||
 | 
					            serializer = BrowsableAPIRendererTests.SimpleSerializer(data={'name': 'Name'})
 | 
				
			||||||
 | 
					            form = self.renderer.render_form_for_serializer(serializer)
 | 
				
			||||||
 | 
					            assert isinstance(form, str), 'Must return form for serializer'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.subTest('ListSerializer'):
 | 
				
			||||||
 | 
					            list_serializer = BrowsableAPIRendererTests.SimpleSerializer(data=[{'name': 'Name'}], many=True)
 | 
				
			||||||
 | 
					            form = self.renderer.render_form_for_serializer(list_serializer)
 | 
				
			||||||
 | 
					            assert form is None, 'Must not return form for list serializer'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_raw_data_form(self):
 | 
				
			||||||
 | 
					        with self.subTest('Serializer'):
 | 
				
			||||||
 | 
					            class DummyGenericViewsetLike(APIView):
 | 
				
			||||||
 | 
					                def get_serializer(self, **kwargs):
 | 
				
			||||||
 | 
					                    return BrowsableAPIRendererTests.SimpleSerializer(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                def get(self, request):
 | 
				
			||||||
 | 
					                    response = Response()
 | 
				
			||||||
 | 
					                    response.view = self
 | 
				
			||||||
 | 
					                    return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                post = get
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            view = DummyGenericViewsetLike.as_view()
 | 
				
			||||||
 | 
					            _request = APIRequestFactory().get('/')
 | 
				
			||||||
 | 
					            request = Request(_request)
 | 
				
			||||||
 | 
					            response = view(_request)
 | 
				
			||||||
 | 
					            view = response.view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            raw_data_form = self.renderer.get_raw_data_form({'name': 'Name'}, view, 'POST', request)
 | 
				
			||||||
 | 
					            assert raw_data_form['_content'].initial == '{\n    "name": ""\n}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.subTest('ListSerializer'):
 | 
				
			||||||
 | 
					            class DummyGenericViewsetLike(APIView):
 | 
				
			||||||
 | 
					                def get_serializer(self, **kwargs):
 | 
				
			||||||
 | 
					                    return BrowsableAPIRendererTests.SimpleSerializer(many=True, **kwargs)  # returns ListSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                def get(self, request):
 | 
				
			||||||
 | 
					                    response = Response()
 | 
				
			||||||
 | 
					                    response.view = self
 | 
				
			||||||
 | 
					                    return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                post = get
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            view = DummyGenericViewsetLike.as_view()
 | 
				
			||||||
 | 
					            _request = APIRequestFactory().get('/')
 | 
				
			||||||
 | 
					            request = Request(_request)
 | 
				
			||||||
 | 
					            response = view(_request)
 | 
				
			||||||
 | 
					            view = response.view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            raw_data_form = self.renderer.get_raw_data_form([{'name': 'Name'}], view, 'POST', request)
 | 
				
			||||||
 | 
					            assert raw_data_form['_content'].initial == '[\n    {\n        "name": ""\n    }\n]'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_get_description_returns_empty_string_for_401_and_403_statuses(self):
 | 
					    def test_get_description_returns_empty_string_for_401_and_403_statuses(self):
 | 
				
			||||||
        assert self.renderer.get_description({}, status_code=401) == ''
 | 
					        assert self.renderer.get_description({}, status_code=401) == ''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user