Search code examples
pythonjsonsqlalchemymarshmallow

Serializer error with sqlachemy and marshmallow


According to the official documentation I try to get all instances of the Vehicle class in json format

Session = sessionmaker(bind=engine)
session = Session()
from models import Vehicle
from marshmallow_sqlalchemy import ModelSchema


class VehicleShema(ModelSchema):
    class Meta:
        model = Vehicle

vehicles = session.query(Vehicle).all()

vehicle_schema = VehicleShema()

session.add(vehicles)
session.commit()

dump_data = vehicle_schema.dump(vehicles)

print(dump_data)

But get an error

    raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.list' is not mapped

I think the problem may be the definition of queriset vehicles = session.query(Vehicle).all() but but I don't find another way to do it.

Then I call only one instance vehicles = session.query(Vehicle).first() all works fine.

error traceback

Traceback (most recent call last):
  File "/home/y700/projects/viastart/sqlalchemy/orm/session.py", line 1955, in add
    state = attributes.instance_state(instance)
AttributeError: 'list' object has no attribute '_sa_instance_state'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "get_vehisle_by_id.py", line 11, in <module>
    session.add(vehicles)
  File "/home/y700/projects/viastart/sqlalchemy/orm/session.py", line 1957, in add
    raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.list' is not mapped

Solution

  • Per my comment use schema.dump(vehicles, many=True):

    To expand you'll likely end up wanting to use some utility like the following:

    def dumpData(load_object, schema, many=False):
        try:
            answer = schema.dump(load_object, many=many)
        except ValidationError as errors:
            raise InvalidDump(errors, status_code=400)
        return answer
    
    class InvalidDump(Exception):
        """error for dumping data"""
        status_code = 400
    
        def __init__(self, message, status_code=None, payload=None):
            Exception.__init__(self)
            self.message = message
            if status_code is not None:
                self.status_code = status_code
            self.payload = payload
    
        def to_dict(self):
            """include marshmallow validation errors in response"""
            rv = dict(self.payload or ())
            rv['message'] = self.message.messages
            return rv
    

    Then for each data dump you create a version with that marshmallow schema.

    def dumpVehicle(load_object, many=False):
        return dumpData(load_object, schema=vehicle_schema_full, many=many)