def to_internal_value(self, data): """ List of dicts of native values <- List of dicts of primitive datatypes. """ if html.is_html_input(data): data = html.parse_html_list(data) if not isinstance(data, list): message = self.error_messages['not_a_list'].format( input_type=type(data).__name__ ) raise ValidationError({ api_settings.NON_FIELD_ERRORS_KEY: [message] }) ret = [] errors = ReturnList(serializer=self) for item in data: try: validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) else: ret.append(validated) errors.append({}) if any(errors): raise ValidationError(errors) return ret
def to_representation(self, instance): """Add addditonal data for the ViewFeatureSerializer. For most features, all the related data is cachable, and no database reads are required with a warm cache. For some features, such as the root node for CSS, the subtree is huge, and the descendant feature PKs won't fit in the cache. In these cases, a couple of database reads are required to get the descendant feature PKs, which are then paginated to reduce the huge amount of related data. """ # Load the paginated descendant features if instance is None: # This happens when OPTIONS is called from browsable API return None self.add_sources(instance) ret = OrderedDict() fields = self._readable_fields for field in fields: attribute = field.get_attribute(instance) assert attribute is not None, ( 'field.get_attribute return None for instance %s, field %s' % (instance, field)) field_ret = field.to_representation(attribute) if isinstance(field, ListSerializer): # Wrap lists of related resources in a ReturnList, so that the # renderer has access to the serializer field_ret = ReturnList(field_ret, serializer=field) ret[field.field_name] = field_ret return ReturnDict(ret, serializer=self)
def test_compatibility_return_collections(self): """ When the input with ReturnDict and ReturnList collections is processed by camelize() and then by underscorize(), the result should be same. Serializers should be preserved in all nested ReturnDict and ReturnList collections. """ fake_serializer_instance_1 = (42, ) fake_serializer_instance_2 = (42, ) fake_serializer_instance_3 = (42, ) input = ReturnDict( [("title_display", 1), ("a_list", ReturnList([ 1, "two_three", ReturnDict([("threee_four", 5)], serializer=fake_serializer_instance_3) ], serializer=fake_serializer_instance_2)), ("a_tuple", ("one_two", 3))], serializer=fake_serializer_instance_1) result = underscorize(camelize(input)) self.assertEqual(result, input) self.assertIs(result.serializer, input.serializer) self.assertIs(result['a_list'].serializer, input['a_list'].serializer) self.assertIs(result['a_list'][2].serializer, input['a_list'][2].serializer)
def data(self): if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'): msg = ('When a serializer is passed a `data` keyword argument you ' 'must call `.is_valid()` before attempting to access the ' 'serialized `.data` representation.\n' 'You should either call `.is_valid()` first, ' 'or access `.initial_data` instead.') raise AssertionError(msg) if not hasattr(self, '_data'): if self.instance is not None and not getattr( self, '_errors', None): 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) else: self._data = self.get_initial() if isinstance(self._data, list): self._data = ReturnList(self._data, serializer=self) else: pass return self._data
def _get_error_details(data, default_code=None): """加载错误详情 :param data: 错误对象 :param default_code: 默认错误码 :return: 错误对象 """ if isinstance(data, list): ret = [_get_error_details(item, default_code) for item in data] if isinstance(data, ReturnList): return ReturnList(ret, serializer=data.serializer) return ret elif isinstance(data, dict): ret = { key: _get_error_details(value, default_code) for key, value in data.items() } if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return ret elif isinstance(data, Trans): return data text = force_text(data) code = getattr(data, 'code', default_code) return exceptions.ErrorDetail(text, code)
def data(self): # call grandparent's property ret = super(serializers.Serializer, self).data if isinstance(ret, dict): return ReturnDict(ret, serializer=self) if isinstance(ret, list): return ReturnList(ret, serializer=self) return ret
def data(self): """Get the data, after performing post-processing if necessary.""" data = super(DynamicListSerializer, self).data processed_data = ReturnDict( SideloadingProcessor(self, data).data, serializer=self) if self.child.envelope else ReturnList( data, serializer=self) return processed_data
def data(self): """Get the data, after performing post-processing if necessary.""" if not hasattr(self, '_sideloaded_data'): data = super(DynamicListSerializer, self).data if self.child.sideload: self._sideloaded_data = ReturnDict(SideloadingProcessor( self, data).data, serializer=self) else: self._sideloaded_data = ReturnList(data, serializer=self) return self._sideloaded_data
def data(self): ret = super(serializers.ListSerializer, self).data if isinstance(ret, dict): # Override to make sure dict is preserved return ReturnDict(ret, serializer=self) elif inspect.isgenerator(ret): # Override to make sure the generator is preserved return ReturnGenerator(ret, serializer=self) else: # Normal behavior return ReturnList(ret, serializer=self)
def test_return_list(self): """ camelize() should convert keys in all objects contained in an instance of rest_framework.utils.serializer_helpers.ReturnList and keep the same serializer. """ fake_serializer_instance = (42, ) input = ReturnList([{ "title_display": 1 }, { "title_field": 2 }], serializer=fake_serializer_instance) output = ReturnList([{ "titleDisplay": 1 }, { "titleField": 2 }], serializer=fake_serializer_instance) result = camelize(input) self.assertEqual(result, output) self.assertIs(result.serializer, output.serializer)
def test_renderer_works_correctly_with_return_list(self): """ Ensure that rest_framework.utils.serializer_helpers.ReturnList is serialized correctly. """ test_list = [{"1": 1}] rendered = self.renderer.render( data=ReturnList(test_list, serializer=None), media_type="application/json", renderer_context={}, ) reloaded = orjson.loads(rendered) self.assertEqual(reloaded, test_list)
def _force_text_recursive(data): """ Descend into a nested data structure, forcing any lazy translation strings into plain text. """ if isinstance(data, list): ret = [_force_text_recursive(item) for item in data] if isinstance(data, ReturnList): return ReturnList(ret, serializer=data.serializer) return data elif isinstance(data, dict): ret = dict([(key, _force_text_recursive(value)) for key, value in data.items()]) if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return data return force_text(data)
def get_error_details(data, default_code=None): if isinstance(data, list): ret = [get_error_details(item, default_code) for item in data] if isinstance(data, ReturnList): return ReturnList(ret, serializer=data.serializer) return ret elif isinstance(data, dict): ret = { key: get_error_details(value, default_code) for key, value in data.items() } if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return ret text = force_str(data) code = getattr(data, 'code', default_code) return ErrorDetail(text, code)
def finalize_response(self, request, response, *args, **kwargs): """ If the requested format is a spreadsheet, format the cell values before rendering the spreadsheet. Also perform the functionality of XLSXFileMixin. """ response = super(XLSXFormatterMixin, self).finalize_response(request, response, *args, **kwargs) # If this is a spreadsheet response, intercept and format. if isinstance( response, Response) and response.accepted_renderer.format == "xlsx": self._field_dict = {} if isinstance(response.data, ReturnList): new_data = [ OrderedDict( [self._format_cell(k, v) for k, v in row.items()]) for row in response.data ] response.data = ReturnList(new_data, serializer=response.data.serializer) elif isinstance(response.data, ReturnDict): new_data = OrderedDict([ self._format_cell(k, v) for k, v in response.data.items() ]) response.data = ReturnDict(new_data, serializer=response.data.serializer) elif isinstance(response.data, dict): # If this is not a proper spreadsheet response (ex: object does not exist), # then return the response in JSON format. response = Response(response.data) response.accepted_renderer = JSONRenderer() response.accepted_media_type = "application/json" response.renderer_context = {} return response response["Content-Disposition"] = "attachment; filename={}".format( self.get_filename()) return response
def wrap_paginated(self, data, renderer_context): """Convert paginated data to JSON API with meta""" pagination_keys = ['count', 'next', 'previous', 'results'] for key in pagination_keys: if not (data and key in data): raise WrapperNotApplicable('Not paginated results') view = renderer_context.get("view", None) model = self.model_from_obj(view) resource_type = self.model_to_resource_type(model) try: from rest_framework.utils.serializer_helpers import ReturnList results = ReturnList( data["results"], serializer=data.serializer.fields["results"], ) except ImportError: results = data["results"] # Use default wrapper for results wrapper = self.wrap_default(results, renderer_context) # Add pagination metadata pagination = self.dict_class() pagination['previous'] = data['previous'] pagination['next'] = data['next'] pagination['count'] = data['count'] wrapper.setdefault('meta', self.dict_class()) wrapper['meta'].setdefault('pagination', self.dict_class()) wrapper['meta']['pagination'].setdefault( resource_type, self.dict_class()).update(pagination) return wrapper
def _force_text_recursive(data): """ Descend into a nested data structure, forcing any lazy translation strings into plain text. This modified version keeps tuples as is """ if isinstance(data, (list, tuple)): ret = [_force_text_recursive(item) for item in data] if isinstance(data, ReturnList): return ReturnList(ret, serializer=data.serializer) if isinstance(data, tuple): return tuple(ret) return ret elif isinstance(data, dict): ret = { key: _force_text_recursive(value) for key, value in data.items() } if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return ret return force_text(data)
def _get_error_details(data, default_code=None): """ Descend into a nested data structure, forcing any lazy translation strings or strings into `ErrorDetail`. """ if isinstance(data, list): ret = [_get_error_details(item, default_code) for item in data] if isinstance(data, ReturnList): return ReturnList(ret, serializer=data.serializer) return ret elif isinstance(data, dict): ret = { key: _get_error_details(value, default_code) for key, value in data.items() } if isinstance(data, ReturnDict): return ReturnDict(ret, serializer=data.serializer) return ret text = force_text(data) code = getattr(data, 'code', default_code) return ErrorDetail(text, code)
def make_list(self, data_list, serializer): list_serializer = ListSerializer(child=serializer) return ReturnList(data_list, serializer=list_serializer)
def errors(self): ret = super(ListSerializer, self).errors if isinstance(ret, dict): return ReturnDict(ret, serializer=self) return ReturnList(ret, serializer=self)
def test_encode_empty_returnlist(self): """ Tests encoding an empty ReturnList """ foo = ReturnList(serializer=None) assert self.encoder.default(foo) == []
def data_list(self): super().data return ReturnList(self._data, serializer=self)
def data(self): ret = super(serializers.Serializer, self).data return ReturnList(ret, serializer=self)
def data(self): returnlist = super().data fieldname = self.child.Meta.listresults_field return OrderedDict( {fieldname: ReturnList(returnlist, serializer=self)})