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)
 | 
			
		||||
 | 
			
		||||
    def render_form_for_serializer(self, serializer):
 | 
			
		||||
        if isinstance(serializer, serializers.ListSerializer):
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        if hasattr(serializer, 'initial_data'):
 | 
			
		||||
            serializer.is_valid()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -555,10 +558,13 @@ class BrowsableAPIRenderer(BaseRenderer):
 | 
			
		|||
                context['indent'] = 4
 | 
			
		||||
 | 
			
		||||
                # strip HiddenField from output
 | 
			
		||||
                is_list_serializer = isinstance(serializer, serializers.ListSerializer)
 | 
			
		||||
                serializer = serializer.child if is_list_serializer else serializer
 | 
			
		||||
                data = serializer.data.copy()
 | 
			
		||||
                for name, field in serializer.fields.items():
 | 
			
		||||
                    if isinstance(field, serializers.HiddenField):
 | 
			
		||||
                        data.pop(name, None)
 | 
			
		||||
                data = [data] if is_list_serializer else data
 | 
			
		||||
                content = renderer.render(data, accepted, context)
 | 
			
		||||
                # Renders returns bytes, but CharField expects a str.
 | 
			
		||||
                content = content.decode()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -633,6 +633,9 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
 | 
			
		|||
    class AuthExampleViewSet(ExampleViewSet):
 | 
			
		||||
        permission_classes = [permissions.IsAuthenticated]
 | 
			
		||||
 | 
			
		||||
    class SimpleSerializer(serializers.Serializer):
 | 
			
		||||
        name = serializers.CharField()
 | 
			
		||||
 | 
			
		||||
    router = SimpleRouter()
 | 
			
		||||
    router.register('examples', ExampleViewSet, basename='example')
 | 
			
		||||
    router.register('auth-examples', AuthExampleViewSet, basename='auth-example')
 | 
			
		||||
| 
						 | 
				
			
			@ -640,6 +643,62 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
 | 
			
		|||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        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):
 | 
			
		||||
        assert self.renderer.get_description({}, status_code=401) == ''
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user