def delete_object(self, obj, view_kwargs): """Delete an object through sqlalchemy :param DeclarativeMeta item: an item from sqlalchemy :param dict view_kwargs: kwargs from the resource view """ if obj is None: url_field = getattr(self, "url_field", "id") filter_value = view_kwargs[url_field] raise ObjectNotFound( f"{self.model.__name__}: {filter_value} not found", source={"parameter": url_field}) self.before_delete_object(obj, view_kwargs) for i_plugins in self.resource.plugins: try: i_plugins.data_layer_delete_object_clean_data( obj=obj, view_kwargs=view_kwargs, self_json_api=self) except PluginMethodNotImplementedError: pass self.session.delete(obj) try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e except Exception as e: self.session.rollback() raise JsonApiException("Delete object error: " + str(e)) self.after_delete_object(obj, view_kwargs)
def update_object(self, obj, data, view_kwargs): """Update an object through sqlalchemy :param DeclarativeMeta obj: an object from sqlalchemy :param dict data: the data validated by marshmallow :param dict view_kwargs: kwargs from the resource view :return boolean: True if object have changed else False """ if obj is None: url_field = getattr(self, "url_field", "id") filter_value = view_kwargs[url_field] raise ObjectNotFound( f"{self.model.__name__}: {filter_value} not found", source={"parameter": url_field}) self.before_update_object(obj, data, view_kwargs) relationship_fields = get_relationships(self.resource.schema, model_field=True) nested_fields = get_nested_fields(self.resource.schema, model_field=True) join_fields = relationship_fields + nested_fields for i_plugins in self.resource.plugins: try: data = i_plugins.data_layer_update_object_clean_data( data=data, obj=obj, view_kwargs=view_kwargs, join_fields=join_fields, self_json_api=self, ) except PluginMethodNotImplementedError: pass for key, value in data.items(): if hasattr(obj, key) and key not in join_fields: setattr(obj, key, value) self.apply_relationships(data, obj) self.apply_nested_fields(data, obj) try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e except Exception as e: self.session.rollback() orig_e = getattr(e, "orig", object) message = getattr(orig_e, "args", []) message = message[0] if message else None e = message if message else e raise JsonApiException("Update object error: " + str(e), source={"pointer": "/data"}) self.after_update_object(obj, data, view_kwargs)
def query(self, view_kwargs): query_ = self.session.query(Computer) if view_kwargs.get('id') is not None: try: self.session.query(Person).filter_by(id=view_kwargs['id']).one() except NoResultFound: raise ObjectNotFound({'parameter': 'id'}, "Person: {} not found".format(view_kwargs['id'])) else: query_ = query_.join(Person).filter(Person.id == view_kwargs['id']) return query_
def event_update_avatar(self, *args, id: int = None, **view_kwargs): # language=YAML """ --- summary: Update user's avatar tags: - User parameters: - in: path name: id required: True type: integer format: int32 description: "user's id" requestBody: content: multipart/form-data: schema: type: object properties: new_avatar: type: string format: binary consumes: - multipart/form-data responses: 201: content: application/json: schema: type: object properties: avatar_url: type: string example: "uploads/avatar.gif" """ avatar = request.files.get("new_avatar") if not avatar: raise BadRequest( "avatar file is required! please fill `new_avatar` form field") user = User.query.filter_by(id=id).one_or_none() if user is None: raise ObjectNotFound( "User #{} not found".format(id), source={"parameter": "id"}, ) filename = avatar.filename avatar_path = str(UPLOADS_DIR / filename) avatar.save(avatar_path) user.avatar_path = str(UPLOADS_DIR_NAME / filename) db.session.commit() return {"avatar_url": user.avatar_path}, 201
def before_get_object(self, view_kwargs): if view_kwargs.get('computer_id') is not None: try: computer = self.session.query(Computer).filter_by(id=view_kwargs['computer_id']).one() except NoResultFound: raise ObjectNotFound({'parameter': 'computer_id'}, "Computer: {} not found".format(view_kwargs['computer_id'])) else: if computer.person is not None: view_kwargs['id'] = computer.person.id else: view_kwargs['id'] = None
def get_relationship(self, relationship_field, related_type_, related_id_field, view_kwargs): """Get a relationship :param str relationship_field: the model attribute used for relationship :param str related_type_: the related resource type :param str related_id_field: the identifier field of the related model :param dict view_kwargs: kwargs from the resource view :return tuple: the object and related object(s) """ self.before_get_relationship(relationship_field, related_type_, related_id_field, view_kwargs) obj = self.get_object(view_kwargs) if obj is None: url_field = getattr(self, "url_field", "id") filter_value = view_kwargs[url_field] raise ObjectNotFound( f"{self.model.__name__}: {filter_value} not found", source={"parameter": url_field}) if not hasattr(obj, relationship_field): raise RelationNotFound( f"{obj.__class__.__name__} has no attribute {relationship_field}" ) related_objects = getattr(obj, relationship_field) if related_objects is None: return obj, related_objects self.after_get_relationship( obj, related_objects, relationship_field, related_type_, related_id_field, view_kwargs, ) if isinstance(related_objects, InstrumentedList): return obj, [{ "type": related_type_, "id": getattr(obj_, related_id_field) } for obj_ in related_objects] else: return obj, { "type": related_type_, "id": getattr(related_objects, related_id_field) }
def get(self, *args, **kwargs): """Get object details""" self.before_get(args, kwargs) qs = self.qs_manager_class(request.args, self.schema) obj = self.get_object(kwargs, qs) if obj is None: url_field = getattr(self._data_layer, "url_field", "id") value = f" '{kwargs.get(url_field)}'" if kwargs.get( url_field) else "" raise ObjectNotFound( f"{self.data_layer['model'].__name__}{value} not found.") self.before_marshmallow(args, kwargs) schema = compute_schema(self.schema, getattr(self, "get_schema_kwargs", dict()), qs, qs.include) for i_plugins in self.plugins: try: i_plugins.after_init_schema_in_resource_detail_get( *args, schema=schema, model=self.data_layer["model"], **kwargs) except PluginMethodNotImplementedError: pass result = schema.dump(obj) final_result = self.after_get(result) return final_result
def delete_relationship(self, json_data, relationship_field, related_id_field, view_kwargs): """Delete a relationship :param dict json_data: the request params :param str relationship_field: the model attribute used for relationship :param str related_id_field: the identifier field of the related model :param dict view_kwargs: kwargs from the resource view """ self.before_delete_relationship(json_data, relationship_field, related_id_field, view_kwargs) obj = self.get_object(view_kwargs) if obj is None: url_field = getattr(self, "url_field", "id") filter_value = view_kwargs[url_field] raise ObjectNotFound( f"{self.model.__name__}: {filter_value} not found", source={"parameter": url_field}) if not hasattr(obj, relationship_field): raise RelationNotFound( f"{obj.__class__.__name__} has no attribute {relationship_field}" ) related_model = getattr(obj.__class__, relationship_field).property.mapper.class_ updated = False if isinstance(json_data["data"], list): obj_ids = { str(getattr(obj__, related_id_field)) for obj__ in getattr(obj, relationship_field) } for obj_ in json_data["data"]: if obj_["id"] in obj_ids: getattr(obj, relationship_field).remove( self.get_related_object(related_model, related_id_field, obj_)) updated = True else: setattr(obj, relationship_field, None) updated = True try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e except Exception as e: self.session.rollback() raise JsonApiException("Delete relationship error: " + str(e)) self.after_delete_relationship(obj, updated, json_data, relationship_field, related_id_field, view_kwargs) return obj, updated
def update_relationship(self, json_data, relationship_field, related_id_field, view_kwargs): """Update a relationship :param dict json_data: the request params :param str relationship_field: the model attribute used for relationship :param str related_id_field: the identifier field of the related model :param dict view_kwargs: kwargs from the resource view :return boolean: True if relationship have changed else False """ self.before_update_relationship(json_data, relationship_field, related_id_field, view_kwargs) obj = self.get_object(view_kwargs) if obj is None: url_field = getattr(self, "url_field", "id") filter_value = view_kwargs[url_field] raise ObjectNotFound( f"{self.model.__name__}: {filter_value} not found", source={"parameter": url_field}) if not hasattr(obj, relationship_field): raise RelationNotFound( f"{obj.__class__.__name__} has no attribute {relationship_field}" ) related_model = getattr(obj.__class__, relationship_field).property.mapper.class_ updated = False if isinstance(json_data["data"], list): related_objects = [] for obj_ in json_data["data"]: related_objects.append( self.get_related_object(related_model, related_id_field, obj_)) obj_ids = { getattr(obj__, related_id_field) for obj__ in getattr(obj, relationship_field) } new_obj_ids = { getattr(related_object, related_id_field) for related_object in related_objects } if obj_ids != new_obj_ids: setattr(obj, relationship_field, related_objects) updated = True else: related_object = None if json_data["data"] is not None: related_object = self.get_related_object( related_model, related_id_field, json_data["data"]) obj_id = getattr(getattr(obj, relationship_field), related_id_field, None) new_obj_id = getattr(related_object, related_id_field, None) if obj_id != new_obj_id: setattr(obj, relationship_field, related_object) updated = True try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e except Exception as e: self.session.rollback() raise JsonApiException("Update relationship error: " + str(e)) self.after_update_relationship(obj, updated, json_data, relationship_field, related_id_field, view_kwargs) return obj, updated