raise error when calling .data in an invalid serializer

This commit is contained in:
Turfa Auliarachman 2019-03-25 23:42:27 +07:00
parent b25d245b89
commit 9280d7f811
5 changed files with 30 additions and 9 deletions

View File

@ -34,6 +34,7 @@ from rest_framework.settings import api_settings
from rest_framework.utils import encoders, json
from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework.utils.field_mapping import ClassLookupDict
from rest_framework.utils.serializer_helpers import ReturnDict
def zero_as_none(value):
@ -522,12 +523,14 @@ class BrowsableAPIRenderer(BaseRenderer):
return self.render_form_for_serializer(serializer)
def render_form_for_serializer(self, serializer):
if hasattr(serializer, 'initial_data'):
serializer.is_valid()
if hasattr(serializer, 'initial_data') and not serializer.is_valid():
data = ReturnDict(serializer.get_initial(), serializer=serializer)
else:
data = serializer.data
form_renderer = self.form_renderer_class()
return form_renderer.render(
serializer.data,
data,
self.accepted_media_type,
{'style': {'template_pack': 'rest_framework/horizontal'}}
)

View File

@ -262,6 +262,9 @@ class BaseSerializer(Field):
self._data = self.to_representation(self.instance)
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
self._data = self.to_representation(self.validated_data)
elif hasattr(self, '_validated_data') and getattr(self, '_errors', None):
msg = 'You can not access `.data` in an invalid serializer.'
raise AssertionError(msg)
else:
self._data = self.get_initial()
return self._data
@ -547,7 +550,13 @@ class Serializer(BaseSerializer):
def __getitem__(self, key):
field = self.fields[key]
value = self.data.get(key)
# If the data is not valid, return the initial data
if not hasattr(self, '_data') and hasattr(self, '_validated_data') and getattr(self, '_errors', None):
value = self.get_initial().get(key)
else:
value = self.data.get(key)
error = self.errors.get(key) if hasattr(self, '_errors') else None
if isinstance(field, Serializer):
return NestedBoundField(field, value, error)

View File

@ -13,6 +13,7 @@ from django.utils.safestring import SafeData, mark_safe
from rest_framework.compat import apply_markdown, pygments_highlight
from rest_framework.renderers import HTMLFormRenderer
from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework.utils.urls import replace_query_param
register = template.Library()
@ -79,9 +80,14 @@ def get_pagination_html(pager):
@register.simple_tag
def render_form(serializer, template_pack=None):
if hasattr(serializer, 'initial_data') and not serializer.is_valid():
data = ReturnDict(serializer.get_initial(), serializer=serializer)
else:
data = serializer.data
style = {'template_pack': template_pack} if template_pack else {}
renderer = HTMLFormRenderer()
return renderer.render(serializer.data, None, {'style': style})
return renderer.render(data, None, {'style': style})
@register.simple_tag

View File

@ -499,7 +499,7 @@ class TestHTMLFormRenderer(TestCase):
test_field = serializers.CharField()
self.renderer = HTMLFormRenderer()
self.serializer = TestSerializer(data={})
self.serializer = TestSerializer(data={'test_field': 'test'})
def test_render_with_default_args(self):
self.serializer.is_valid()

View File

@ -86,15 +86,17 @@ class TestSerializer:
serializer = self.Serializer(data={'char': 'abc'})
assert not serializer.is_valid()
assert serializer.validated_data == {}
assert serializer.data == {'char': 'abc'}
assert serializer.errors == {'integer': ['This field is required.']}
with pytest.raises(AssertionError):
serializer.data
def test_invalid_datatype(self):
serializer = self.Serializer(data=[{'char': 'abc'}])
assert not serializer.is_valid()
assert serializer.validated_data == {}
assert serializer.data == {}
assert serializer.errors == {'non_field_errors': ['Invalid data. Expected a dictionary, but got list.']}
with pytest.raises(AssertionError):
serializer.data
def test_partial_validation(self):
serializer = self.Serializer(data={'char': 'abc'}, partial=True)
@ -208,11 +210,12 @@ class TestSerializer:
serializer = ExampleSerializer(data=data)
assert not serializer.is_valid()
assert serializer.data == data
assert serializer.validated_data == {}
assert serializer.errors == {'char': [
exceptions.ErrorDetail(string='Raised error', code='invalid')
]}
with pytest.raises(AssertionError):
serializer.data
class TestValidateMethod: