예제 #1
0
    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
예제 #2
0
 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
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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
                })