Update row (SQLAlchemy) with data from marshmallow

gcerar picture gcerar · Aug 8, 2015 · Viewed 10.7k times · Source

I'm using Flask, Flask-SQLAlchemy, Flask-Marshmallow + marshmallow-sqlalchemy, trying to implement REST api PUT method. I haven't found any tutorial using SQLA and Marshmallow implementing update.

Here is the code:

class NodeSchema(ma.Schema):
    # ...


class NodeAPI(MethodView):
    decorators = [login_required, ]
    model = Node

    def get_queryset(self):
        if g.user.is_admin:
            return self.model.query
        return self.model.query.filter(self.model.owner == g.user)

    def put(self, node_id):
        json_data = request.get_json()
        if not json_data:
            return jsonify({'message': 'Invalid request'}), 400

        # Here is part which I can't make it work for me
        data, errors = node_schema.load(json_data)
        if errors:
            return jsonify(errors), 422

        queryset = self.get_queryset()


        node = queryset.filter(Node.id == node_id).first_or_404()
        # Here I need some way to update this object
        node.update(data) #=> raises AttributeError: 'Node' object has no attribute 'update'

        # Also tried:
        # node = queryset.filter(Node.id == node_id)
        # node.update(data) <-- It doesn't if know there is any object
        # Wrote testcase, when user1 tries to modify node of user2. Node doesn't change (OK), but user1 gets status code 200 (NOT OK).

        db.session.commit()
        return jsonify(), 200

Answer

Jair Perrut picture Jair Perrut · Apr 5, 2016

UPDATED

Extending the ModelSchema from marshmallow-sqlalchemy instead Flask-Marshmallow you have:

load(data, session=None, instance=None, *args, **kwargs)

Then you have to pass the object being edited as parameter in schema.load(), like this:

node_schema.load(json_data, instance=Node().query.get(node_id))

And if you want to load without all required fields of Model, you can add the partial=True, like this:

node_schema.load(json_data, instance=Node().query.get(node_id), partial=True)

See the docs marshmallow_sqlalchemy.ModelSchema.load