def raw_data(self): """Validate and return parsed JSON payload.""" if not hasattr(self, '_raw_data'): if request.method in ('PUT', 'POST') or request.data: if request.mimetype and 'json' not in request.mimetype: raise ValidationError({ 'error': "Please send valid JSON with a 'Content-Type: application/json' header." }) if request.headers.get('Transfer-Encoding') == 'chunked': raise ValidationError({ 'error': "Chunked Transfer-Encoding is not supported." }) try: self._raw_data = json.loads( request.data.decode('utf-8'), parse_constant=self._enforce_strict_json) except ValueError: raise ValidationError( {'error': 'The request contains invalid JSON.'}) if not isinstance(self._raw_data, dict): raise ValidationError( {'error': 'JSON data must be a dict.'}) else: self._raw_data = {} return self._raw_data
def handle_validation_error(self, e): if isinstance(e, ValidationError): raise e elif isinstance(e, mongoengine.ValidationError): raise ValidationError(serialize_mongoengine_validation_error(e)) else: raise e
def get_objects(self): """ Return objects fetched from the database based on all the parameters of the request that's currently being processed. Params: - Custom queryset can be passed via `qs`. Otherwise `self.get_queryset` is used. - Pass `qfilter` function to modify the queryset. """ params = self.params # Apply filters and ordering, based on the params supplied by the # request query_filter = self.apply_filters(params) query_order = self.apply_ordering(params) # Create the query cureser query_courser = self.document.find(query_filter) # Apply limit and skip to the queryset limit = None if self.view_method == methods.BulkUpdate: # limit the number of objects that can be bulk-updated at a time limit = self.bulk_update_limit query_courser = query_courser.limit(limit) else: skip, limit = self.get_skip_and_limit(params) query_courser = query_courser.skip(skip).limit(limit + 1) if query_order: query_courser = query_courser.sort(query_order) count = query_courser.count() # Evaluate the queryset objs = list(query_courser) # Raise a validation error if bulk update would result in more than # bulk_update_limit updates if self.view_method == methods.BulkUpdate and len( objs) >= self.bulk_update_limit: raise ValidationError({ 'errors': [ "It's not allowed to update more than %d objects at once" % self.bulk_update_limit ] }) # Determine the value of has_more if self.view_method != methods.BulkUpdate and self.paginate: has_more = len(objs) > limit if has_more: objs = objs[:-1] else: has_more = None return objs, has_more, count
def get_skip_and_limit(self, params=None): """ Perform validation and return sanitized values for _skip and _limit params of the request that's currently being processed. """ max_limit = self.get_max_limit() if params is None: params = self.params if self.paginate: # _limit and _skip validation if not isint(params.get('_limit', 1)): raise ValidationError({ 'error': '_limit must be an integer (got "%s" instead).' % params['_limit'] }) if not isint(params.get('_skip', 1)): raise ValidationError({ 'error': '_skip must be an integer (got "%s" instead).' % params['_skip'] }) if params.get('_limit') and int(params['_limit']) > max_limit: raise ValidationError({ 'error': "The limit you set is larger than the maximum limit for this resource (max_limit = %d)." % max_limit }) if params.get('_skip') and int(params['_skip']) < 0: raise ValidationError({ 'error': '_skip must be a non-negative integer (got "%s" instead).' % params['_skip'] }) limit = min(int(params.get('_limit', self.default_limit)), max_limit) # Fetch one more so we know if there are more results. return int(params.get('_skip', 0)), limit else: return 0, max_limit
def validate_request(self, obj=None): """ Validate the request that's currently being processed and fill in the self.data dict that'll later be used to save/update an object. `obj` points to the object that's being updated, or is empty if a new object is being created. """ # When creating or updating a single object, delegate the validation # to a more specific subresource, if it exists if (request.method == 'PUT' and obj) or request.method == 'POST': subresource = self._subresource(obj) if subresource: subresource._raw_data = self.raw_data subresource.validate_request(obj=obj) self.data = subresource.data return # Don't work on original raw data, we may reuse the resource for bulk # updates. self.data = self.raw_data.copy() # Do renaming in two passes to prevent potential multiple renames # depending on dict traversal order. # E.g. if a -> b, b -> c, then a should never be renamed to c. fields_to_delete = [] fields_to_update = {} for k, v in self._rename_fields.items(): if v in self.data: fields_to_update[k] = self.data[v] fields_to_delete.append(v) for k in fields_to_delete: del self.data[k] for k, v in fields_to_update.items(): self.data[k] = v # If CleanCat schema exists on this resource, use it to perform the # validation if self.schema: if request.method == 'PUT' and obj is not None: obj_data = dict([(key, getattr(obj, key)) for key in obj._fields.keys()]) else: obj_data = None schema = self.schema(self.data, obj_data) try: self.data = schema.full_clean() except SchemaValidationError: raise ValidationError({ 'field-errors': schema.field_errors, 'errors': schema.errors })