Exemple #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 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 []
Exemple #2
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
        """
        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
Exemple #3
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__
Exemple #4
0
 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
Exemple #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_
Exemple #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"])
Exemple #7
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(
                "{}: {} 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)
Exemple #8
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(
                "{} 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,
        )