Ejemplo n.º 1
0
    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 SPLIT_REL not in field:
                    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 []
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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(f"{self.schema.__name__} has no attribute {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
Ejemplo n.º 4
0
    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__
Ejemplo n.º 5
0
    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_
Ejemplo n.º 6
0
    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"])
Ejemplo n.º 7
0
    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
        """
        for i_plugins in self.resource.plugins:
            try:
                i_plugins.data_layer_before_create_object(
                    data=data, view_kwargs=view_kwargs, self_json_api=self)
            except PluginMethodNotImplementedError:
                pass

        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

        for i_plugins in self.resource.plugins:
            try:
                data = i_plugins.data_layer_create_object_clean_data(
                    data=data,
                    view_kwargs=view_kwargs,
                    join_fields=join_fields,
                    self_json_api=self,
                )
            except PluginMethodNotImplementedError:
                pass
        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)

        for i_plugins in self.resource.plugins:
            try:
                i_plugins.data_layer_after_create_object(
                    data=data,
                    view_kwargs=view_kwargs,
                    obj=obj,
                    self_json_api=self,
                )
            except PluginMethodNotImplementedError:
                pass

        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(f"Object creation error: {e}",
                                   source={"pointer": "/data"})

        self.after_create_object(obj, data, view_kwargs)

        return obj