def sorting(self): """Return fields to sort by including sort name for SQLAlchemy and row sort parameter for other ORMs :return list: a list of sorting information Example of return value:: [ {'field': 'created_at', 'order': 'desc'}, ] """ if self.qs.get("sort"): sorting_results = [] for sort_field in self.qs["sort"].split(","): field = sort_field.replace("-", "") if field not in self.schema._declared_fields: raise InvalidSort("{} has no attribute {}".format( self.schema.__name__, field)) if field in get_relationships(self.schema): raise InvalidSort( "You can't sort on {} because it is a relationship field" .format(field)) field = get_model_field(self.schema, field) order = "desc" if sort_field.startswith("-") else "asc" sorting_results.append({"field": field, "order": order}) return sorting_results return []
def create_object(self, data, view_kwargs): """Create an object through sqlalchemy :param dict data: the data validated by marshmallow :param dict view_kwargs: kwargs from the resource view :return DeclarativeMeta: an object from sqlalchemy """ self.before_create_object(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 obj = self.model( **{key: value for (key, value) in data.items() if key not in join_fields} ) self.apply_relationships(data, obj) self.apply_nested_fields(data, obj) self.session.add(obj) try: self.session.commit() except JsonApiException as e: self.session.rollback() raise e except Exception as e: self.session.rollback() raise JsonApiException( "Object creation error: " + str(e), source={"pointer": "/data"} ) self.after_create_object(obj, data, view_kwargs) return obj
def related_schema(self): """Get the related schema of a relationship field :return Schema: the related schema """ relationship_field = self.name if relationship_field not in get_relationships(self.schema): raise InvalidFilters( "{} has no relationship attribute {}".format( self.schema.__name__, relationship_field ) ) return self.schema._declared_fields[relationship_field].schema.__class__
def create_object(self, data, kwargs): # This is mostly copied from flapison.data_layers.alchemy relationship_fields = get_relationships(self.schema, model_field=True) nested_fields = get_nested_fields(self.schema, model_field=True) join_fields = relationship_fields + nested_fields new_user = self.data_layer["model"]( **{key: value for (key, value) in data.items() if key not in join_fields} ) self._data_layer.apply_relationships(data, new_user) self._data_layer.apply_nested_fields(data, new_user) # Creating a user requires generating a password new_user.enforce_admin() new_user.set_password(data["password"]) new_user.save() return new_user
def related_model(self): """Get the related model of a relationship field :return DeclarativeMeta: the related model """ relationship_field = self.name if relationship_field not in get_relationships(self.schema): raise InvalidFilters( "{} has no relationship attribute {}".format( self.schema.__name__, relationship_field ) ) return getattr( self.model, get_model_field(self.schema, relationship_field) ).property.mapper.class_
def apply_relationships(self, data, obj): """Apply relationship provided by data to obj :param dict data: data provided by the client :param DeclarativeMeta obj: the sqlalchemy object to plug relationships to :return boolean: True if relationship have changed else False """ relationships_to_apply = [] relationship_fields = get_relationships(self.resource.schema, model_field=True) for key, value in data.items(): if key in relationship_fields: related_model = getattr(obj.__class__, key).property.mapper.class_ schema_field = get_schema_field(self.resource.schema, key) related_id_field = self.resource.schema._declared_fields[ schema_field ].id_field if isinstance(value, list): related_objects = [] for identifier in value: related_object = self.get_related_object( related_model, related_id_field, {"id": identifier} ) related_objects.append(related_object) relationships_to_apply.append( {"field": key, "value": related_objects} ) else: related_object = None if value is not None: related_object = self.get_related_object( related_model, related_id_field, {"id": value} ) relationships_to_apply.append( {"field": key, "value": related_object} ) for relationship in relationships_to_apply: setattr(obj, relationship["field"], relationship["value"])
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( "{}: {} not found".format(self.model.__name__, filter_value), 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 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() raise JsonApiException( "Update object error: " + str(e), source={"pointer": "/data"} ) self.after_update_object(obj, data, view_kwargs)
def _get_relationship_data(self): """Get useful data for relationship management""" relationship_field = request.path.split("/")[-1].replace("-", "_") if relationship_field not in get_relationships(self.schema): raise RelationNotFound( "{} has no attribute {}".format( self.schema.__name__, relationship_field ) ) related_type_ = self.schema._declared_fields[relationship_field].type_ related_id_field = self.schema._declared_fields[relationship_field].id_field model_relationship_field = get_model_field(self.schema, relationship_field) return ( relationship_field, model_relationship_field, related_type_, related_id_field, )