How do I deserialize a marshmallow_jsonapi.flask schema field into a SQLAlchemySchema PostgreSQL JSONB field?

727 views Asked by At

I have a Flask model with a field called metadata of the JSONB type in PostgreSQL.

class Foo(db.Model):
    id = db.Column(db.String(128), primary_key=True)
    metadata = db.Column(JSONB)

I'm serializing that as a marshmallow_jsonapi.flask Schema (ma is my environment's Marshmallow object):

from marshmallow_jsonapi import fields
class FooSchema(ma.SQLAlchemySchema):
    id = fields.Str()
    metadata = fields.Raw()

    class Meta:
        model = Foo
        type_ = "foo"
        self_view = "foo_detail"
        self_view_kwargs = {"foo_detail": "<id>"}
        self_view_many = "foo_list"

Then I'm trying to use a flask_rest_json_api API to deserialize the requests:

from api.models import Foo
from flask_rest_jsonapi import ResourceList
class FooList(ResourceList):
    def get(self):
        schema = FooSchema(many=True)
        query = Foo.query
        return paginate(query, schema)

    def post(self):
        schema = FooSchema()
        foo = schema.load(request.json)

        db.session.add(foo)
        db.session.commit()

When I POST the request, the incoming JSON gets properly deserialized into the foo object as far as I can tell, but the .add() method fails.

...
db.session.add(foo)
...
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.dict' is not mapped

It looks like the ORM is getting a dict that it cannot map to the correct PostgreSQL data type.

Should the ma.SQLAlchemySchema instance use something other than fields.Raw() to serialize the JSONB field? Should I process the Foo instance after calling schema.load()? Any help is appreciated.

1

There are 1 answers

0
alim91 On

try marshmallow_sqlalchemy SQLAlchemyAutoSchema object to automatically generate fields for a model, and set the load_instance to true in metaclass

from marshmallow_jsonapi import fields
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema

class FooSchema(SQLAlchemyAutoSchema):
    id = fields.Str()
    metadata = fields.Raw()

    class Meta:
        model = Foo
        type_ = "foo"
        self_view = "foo_detail"
        self_view_kwargs = {"foo_detail": "<id>"}
        self_view_many = "foo_list"
        load_instance = True # deserialize to model instances