def get(self, *args, **kwargs): """Get item details """ try: item = self.data_layer.get_item(**kwargs) except EntityNotFound as e: return ErrorFormatter.format_error([e.message]), e.status_code qs = QSManager(request.args) schema_kwargs = self.schema.get('get_kwargs', {}) if qs.fields.get(self.resource_type): if schema_kwargs.get('only'): schema_kwargs['only'] = tuple( set(schema_kwargs['only']) & set(self.schema['cls']._declared_fields.keys()) & set(qs.fields[self.resource_type])) else: schema_kwargs['only'] = tuple( set(self.schema['cls']._declared_fields.keys()) & set(qs.fields[self.resource_type])) if schema_kwargs.get('only') and 'id' not in schema_kwargs['only']: schema_kwargs['only'] += ('id', ) schema = self.schema['cls'](**schema_kwargs) result = schema.dump(item) return result.data
def get(self, *args, **kwargs): qs = QSManager(request.args, self.schema) popular_locations = ( db.session.query( Event.searchable_location_name, func.count(Event.id).label('counts') ) .group_by(Event.searchable_location_name) .order_by(desc('counts')) .limit(6) ) locations = [] for location, _ in popular_locations: if location is not None: new_location = EventLocation(name=location) new_location.id = len(locations) locations.append(new_location) schema = EventLocationSchema() result = schema.dump(locations, many=True).data view_kwargs = ( request.view_args if getattr(self, 'view_kwargs', None) is True else {} ) add_pagination_links( result, len(locations), qs, url_for(self.view, **view_kwargs) ) result.update({'meta': {'count': len(locations)}}) return result
def get(self, *args, **kwargs): """Get a relationship details """ relationship_field, related_type_, related_id_field = self._get_relationship_data() related_view = self.schema._declared_fields[relationship_field].related_view related_view_kwargs = self.schema._declared_fields[relationship_field].related_view_kwargs obj, data = self.data_layer.get_relationship(relationship_field, related_type_, related_id_field, **kwargs) for key, value in copy(related_view_kwargs).items(): if isinstance(value, str) and value.startswith('<') and value.endswith('>'): tmp_obj = obj for field in value[1:-1].split('.'): tmp_obj = getattr(tmp_obj, field) related_view_kwargs[key] = tmp_obj result = {'links': {'self': url_for(self.view, **kwargs), 'related': url_for(related_view, **related_view_kwargs)}, 'data': data} qs = QSManager(request.args, self.schema) if qs.include: schema = compute_schema(self.schema, dict(), qs, qs.include) serialized_obj = schema.dump(obj) result['included'] = serialized_obj.data.get('included', dict()) return result
def get(self, *args, **kwargs): """Retrieve a collection of objects""" self.before_get(args, kwargs) qs = QSManager(request.args) objects_count, objects = self.get_collection(qs, kwargs) schema_kwargs = getattr(self, 'get_schema_kwargs', dict()) schema_kwargs.update({'many': True}) schema = compute_schema(self.get_schema(objects, kwargs=kwargs), schema_kwargs, qs, qs.include) result = schema.dump(objects).data self_url = schema.get_top_level_links(result, many=True)['self'] add_pagination_links(result, objects_count, qs, self_url) result.update({'meta': {'count': objects_count}}) self.after_get(result) return result
def delete(self, *args, **kwargs): """Delete relationship(s) """ json_data = request.get_json() relationship_field, related_type_, related_id_field = self._get_relationship_data() if 'data' not in json_data: raise BadRequest('/data', 'You must provide data with a "data" route node') if isinstance(json_data['data'], dict): if 'type' not in json_data['data']: raise BadRequest('/data/type', 'Missing type in "data" node') if 'id' not in json_data['data']: raise BadRequest('/data/id', 'Missing id in "data" node') if json_data['data']['type'] != related_type_: raise InvalidType('/data/type', 'The type field does not match the resource type') if isinstance(json_data['data'], list): for obj in json_data['data']: if 'type' not in obj: raise BadRequest('/data/type', 'Missing type in "data" node') if 'id' not in obj: raise BadRequest('/data/id', 'Missing id in "data" node') if obj['type'] != related_type_: raise InvalidType('/data/type', 'The type provided does not match the resource type') obj_, updated = self.data_layer.delete_relationship(json_data, relationship_field, related_id_field, **kwargs) qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, dict(), qs, qs.include) status_code = 200 if updated is True else 204 return schema.dump(obj_), status_code
def get(self, *args, **kwargs): """Retrieve a collection of objects""" self.before_get(args, kwargs) qs = QSManager(request.args, self.schema) objects_count, objects = self.get_collection(qs, kwargs) schema_kwargs = getattr(self, 'get_schema_kwargs', dict()) schema_kwargs.update({'many': True}) self.before_marshmallow(args, kwargs) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) result = schema.dump(objects).data view_kwargs = request.view_args if getattr(self, 'view_kwargs', None) is True else dict() add_pagination_links(result, objects_count, qs, url_for(self.view, _external=True, **view_kwargs)) result.update({'meta': {'count': objects_count}}) final_result = self.after_get(result) return final_result
def post(self, *args, **kwargs): """Create an object""" qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self, 'post_schema_kwargs', dict()), qs, qs.include + self.default_include) data = self._validate_schema(args, kwargs, schema) if isinstance(data, tuple): return data self.before_post(args, kwargs, data=data) obj = self.create_object(data, kwargs) result = schema.dump(obj) if result['data'].get('links', {}).get('self'): final_result = (result, 201, { 'Location': result['data']['links']['self'] }) else: final_result = (result, 201) result = self.after_post(final_result) return result
def get(self, *args, **kwargs): """Get a relationship details""" self.before_get(args, kwargs) relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data( ) obj, data = self._data_layer.get_relationship(model_relationship_field, related_type_, related_id_field, kwargs) result = { 'links': { 'self': request.path, 'related': self.schema._declared_fields[relationship_field]. get_related_url(obj) }, 'data': data } qs = QSManager(request.args, self.schema) if qs.include: schema = compute_schema(self.schema, dict(), qs, qs.include) serialized_obj = schema.dump(obj) result['included'] = serialized_obj.data.get('included', dict()) final_result = self.after_get(result) return final_result
def get(self, *args, **kwargs): """Retrieve a collection of items """ qs = QSManager(request.args) try: item_count, items = self.data_layer.get_items(qs, **kwargs) except EntityNotFound as e: return ErrorFormatter.format_error([e.message]), e.status_code schema_kwargs = self.schema.get('get_kwargs', {}) if qs.fields.get(self.resource_type): if schema_kwargs.get('only'): schema_kwargs['only'] = tuple( set(schema_kwargs['only']) & set(self.schema['cls']._declared_fields.keys()) & set(qs.fields[self.resource_type])) else: schema_kwargs['only'] = tuple( set(self.schema['cls']._declared_fields.keys()) & set(qs.fields[self.resource_type])) if schema_kwargs.get('only') and 'id' not in schema_kwargs['only']: schema_kwargs['only'] += ('id', ) schema_kwargs.pop('many', None) schema = self.schema['cls'](many=True, **schema_kwargs) result = schema.dump(items) endpoint_kwargs = request.view_args if self.endpoint.get( 'include_view_kwargs') is True else {} add_pagination_links( result.data, item_count, qs, url_for(self.endpoint.get('name'), **endpoint_kwargs)) return result.data
def patch(self, *args, **kwargs): qs = QSManager(request.args, self.schema) schema_kwargs = getattr(self, 'patch_schema_kwargs', dict()) schema_kwargs.update({'partial': True}) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) json_data = request.get_json() or {} self.before_patch(args, kwargs, data=json_data) objs = [] for data in json_data['data']: obj = schema.load({'data': data}).data obj['id'] = data['id'] objs += [obj] result_objs = self.update_list(objs, qs, kwargs) schema_kwargs.update({'many': True}) many_schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) result = many_schema.dump(result_objs).data self.after_patch(result) return (result, 200)
def post(self, *args, **kwargs): """Create an object""" json_data = request.get_json() or {} qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self, 'post_schema_kwargs', dict()), qs, qs.include) try: if isinstance(json_data['data'], list): list_data = [] errors = None for data in json_data['data']: data, obj_errors = schema.load({'data': data}) list_data += [data] else: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 self.before_post(args, kwargs, data=data) if isinstance(json_data['data'], list): objs = self.create_list(list_data, kwargs) result = schema.dump(objs).data final_result = (result, 201) else: obj = self.create_object(data, kwargs) result = schema.dump(obj).data if result['data'].get('links', {}).get('self'): final_result = (result, 201, { 'Location': result['data']['links']['self'] }) else: final_result = (result, 201) result = self.after_post(final_result) return result
def patch(self, *args, **kwargs): """Update a relationship""" json_data = request.get_json() or {} relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data( ) if 'data' not in json_data: raise BadRequest('You must provide data with a "data" route node', source={'pointer': '/data'}) if isinstance(json_data['data'], dict): if 'type' not in json_data['data']: raise BadRequest('Missing type in "data" node', source={'pointer': '/data/type'}) if 'id' not in json_data['data']: raise BadRequest('Missing id in "data" node', source={'pointer': '/data/id'}) if json_data['data']['type'] != related_type_: raise InvalidType( 'The type field does not match the resource type', source={'pointer': '/data/type'}) if isinstance(json_data['data'], list): for obj in json_data['data']: if 'type' not in obj: raise BadRequest('Missing type in "data" node', source={'pointer': '/data/type'}) if 'id' not in obj: raise BadRequest('Missing id in "data" node', source={'pointer': '/data/id'}) if obj['type'] != related_type_: raise InvalidType( 'The type provided does not match the resource type', source={'pointer': '/data/type'}) self.before_patch(args, kwargs, json_data=json_data) obj_, updated = self._data_layer.update_relationship( json_data, model_relationship_field, related_id_field, kwargs) qs = QSManager(request.args, self.schema) includes = qs.include if relationship_field not in qs.include: includes.append(relationship_field) schema = compute_schema(self.schema, dict(), qs, includes) if updated is False: return '', 204 result = schema.dump(obj_).data if result.get('links', {}).get('self') is not None: result['links']['self'] = request.path self.after_patch(result) return result, 200
def patch(self, *args, **kwargs): """Update an object""" json_data = request.get_json() or {} qs = QSManager(request.args, self.schema) schema_kwargs = getattr(self, 'patch_schema_kwargs', dict()) schema_kwargs.update({'partial': True}) self.before_marshmallow(args, kwargs) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) try: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 if 'id' not in json_data['data']: raise BadRequest('Missing id in "data" node', source={'pointer': '/data/id'}) if json_data['data']['id'] != str(kwargs[self.data_layer.get('url_field', 'id')]): raise BadRequest('Value of id does not match the resource identifier in url', source={'pointer': '/data/id'}) self.before_patch(args, kwargs, data=data) obj = self.update_object(data, qs, kwargs) result = schema.dump(obj).data self.after_patch(result) return result
def delete(self, *args, **kwargs): """Delete relationship(s) """ self.before_delete(args, kwargs) json_data = request.get_json() relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data( ) if 'data' not in json_data: raise BadRequest('/data', 'You must provide data with a "data" route node') if isinstance(json_data['data'], dict): if 'type' not in json_data['data']: raise BadRequest('/data/type', 'Missing type in "data" node') if 'id' not in json_data['data']: raise BadRequest('/data/id', 'Missing id in "data" node') if json_data['data']['type'] != related_type_: raise InvalidType( '/data/type', 'The type field does not match the resource type') if isinstance(json_data['data'], list): for obj in json_data['data']: if 'type' not in obj: raise BadRequest('/data/type', 'Missing type in "data" node') if 'id' not in obj: raise BadRequest('/data/id', 'Missing id in "data" node') if obj['type'] != related_type_: raise InvalidType( '/data/type', 'The type provided does not match the resource type') obj_, updated = self._data_layer.delete_relationship( json_data, model_relationship_field, related_id_field, kwargs) qs = QSManager(request.args, self.schema) includes = qs.include if relationship_field not in qs.include: includes.append(relationship_field) schema = compute_schema(self.schema, dict(), qs, includes) status_code = 200 if updated is True else 204 result = schema.dump(obj_).data if result.get('links', {}).get('self') is not None: result['links']['self'] = request.path self.after_delete(result) return result, status_code
def get(self, *args, **kwargs): """Get object details """ obj = self.data_layer.get_object(**kwargs) qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self.opts, 'schema_get_kwargs', dict()), qs, qs.include) result = schema.dump(obj) return result.data
def patch(self, *args, **kwargs): """Update an object """ json_data = request.get_json() qs = QSManager(request.args, self.schema) schema_kwargs = getattr(self.opts, 'schema_patch_kwargs', dict()) schema_kwargs.update({'partial': True}) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) try: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 if 'id' not in json_data['data']: raise BadRequest('/data/id', 'Missing id in "data" node') if json_data['data']['id'] != str(kwargs[getattr(self.data_layer, 'url_field', 'id')]): raise BadRequest('/data/id', 'Value of id does not match the resource identifier in url') obj = self.data_layer.get_object(**kwargs) updated = self.data_layer.update_object(obj, data, **kwargs) result = schema.dump(obj) status_code = 200 if updated is True else 204 return result.data, status_code
def post(self, *args, **kwargs): """Create an object""" json_data = request.get_json() or {} qs = QSManager(request.args) schema = compute_schema(self.get_schema(json_data, is_load=True, kwargs=kwargs), getattr(self, 'post_schema_kwargs', dict()), qs, qs.include) try: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 self.before_post(args, kwargs, data=data) obj = self.create_object(data, kwargs) result = schema.dump(obj).data self.after_post(result) if result['data'].get('links', {}).get('self'): final_result = (result, 201, {'Location': result['data']['links']['self']}) else: final_result = (result, 201) return final_result
def get(self, *args, **kwargs): """Get object details """ self.before_get(args, kwargs) obj = self._data_layer.get_object(kwargs) qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self, 'get_schema_kwargs', dict()), qs, qs.include) result = schema.dump(obj).data self.after_get(result) return result
def get(self, *args, **kwargs): """Get object details""" self.before_get(args, kwargs) qs = QSManager(request.args, self.schema) obj = self.get_object(kwargs, qs) self.before_marshmallow(args, kwargs) schema = compute_schema(self.schema, getattr(self, 'get_schema_kwargs', dict()), qs, qs.include) result = schema.dump(obj) if obj else None final_result = self.after_get(result) return final_result
def get_distinct_sort_fields(schema, model, sort=True): """Due to the poor code of flask-rest-jsonapi, distinct query needed in sessions API to remove duplicate sessions can't be sorted on returning subquery, thus we need to add all sort fields in distinct group and repeat it in sort group as well""" fields = [] qs = QSManager(request.args, schema) for sort_opt in qs.sorting: field = sort_opt['field'] if not hasattr(model, field): continue field = getattr(model, field) if sort: field = getattr(field, sort_opt['order'])() fields.append(field) field = Session.id if sort: field = field.desc() fields.append(field) return fields
def patch(self, *args, **kwargs): """Update an object""" qs = QSManager(request.args, self.schema) schema_kwargs = getattr(self, 'patch_schema_kwargs', dict()) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include + self.default_include) data = self._validate_schema(args, kwargs, schema) if isinstance(data, tuple): return data self.before_patch(args, kwargs, data=data) obj = self.update_object(data, qs, kwargs) result = schema.dump(obj) final_result = self.after_patch(result) return final_result
def post(self, *args, **kwargs): """Create an object """ self.before_post(args, kwargs) json_data = request.get_json() qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self, 'post_schema_kwargs', dict()), qs, qs.include) try: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 obj = self._data_layer.create_object(data, kwargs) result = schema.dump(obj).data self.after_post(result) return result, 201, {'Location': result['data']['links']['self']}
def post(self, *args, **kwargs): """Create an object """ json_data = request.get_json() qs = QSManager(request.args, self.schema) schema = compute_schema(self.schema, getattr(self.opts, 'schema_post_kwargs', dict()), qs, qs.include) try: data, errors = schema.load(json_data) except IncorrectTypeError as e: errors = e.messages for error in errors['errors']: error['status'] = '409' error['title'] = "Incorrect type" return errors, 409 except ValidationError as e: errors = e.messages for message in errors['errors']: message['status'] = '422' message['title'] = "Validation error" return errors, 422 if errors: for error in errors['errors']: error['status'] = "422" error['title'] = "Validation error" return errors, 422 obj = self.data_layer.create_object(data, **kwargs) return schema.dump(obj).data, 201
def get(self, *args, **kwargs): """Retrieve a collection of objects """ qs = QSManager(request.args, self.schema) object_count, objects = self.data_layer.get_collection(qs, **kwargs) schema_kwargs = getattr(self.opts, 'schema_get_kwargs', dict()) schema_kwargs.update({'many': True}) schema = compute_schema(self.schema, schema_kwargs, qs, qs.include) result = schema.dump(objects) view_kwargs = request.view_args if getattr(self.opts, 'view_kwargs', None) is True else dict() add_pagination_links(result.data, object_count, qs, url_for(self.view, **view_kwargs)) return result.data
def test_qs_manager(): with pytest.raises(ValueError): QSManager([], None)