Serialize geometry using flask-marshmallow

Viewed 798

I have a sqlalchemy2 (with geoalchemy extension) model containing geometry data type like so:

class Estate(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    geom = db.Column(Geometry(geometry_type='POLYGON')
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    user = db.relationship('Users', backref='estates')

and the marshmallow schema:

class EstateSchema(ma.ModelSchema):
    class Meta:
        model = Estates

but during attempt of serialization I received following error:

marshmallow_sqlalchemy.exceptions.ModelConversionError: Could not find field column of type <class 'geoalchemy2.types.Geometry'>.

The ModelConversion complaining about WKBElement, because is not defined as a common field.

Question is, how can I modify the code, to get the (de)serializer working with Geometry model field?

2 Answers

I know this is pretty old, but answering now as I just solved this for myself after landing on this question. The way I accomplished it is just by adding a method field to my schema like so:

from marshmallow_sqlalchemy import SQLAlchemySchema, fields
from geoalchemy2.shape import to_shape

from common.models import Node


class NodeSchema(SQLAlchemySchema):
    class Meta:
        model = Node

    geom = fields.fields.Method("geomToPoint")

    def geomToPoint(self, obj):
        return to_shape(obj.geom)

This returns the Geometry field as a Shapely shape field, something like POINT (39.2934324 -123.59348) which is what I was looking for.

marshmallow_sqlalchemy do not know how to serialize the field geom of type Geometry. This is because GeoAlchemy is not directly supported in marshmallow. In order to solve this you need to write a custom ModelConverter which tells marshmallow how to serialize a field of type Geometry.

from geoalchemy2.types import Geometry as GeometryType
from marshmallow_sqlchemy.convert import ModelConverter as BaseModelConverter


class ModelConverter(BaseModelConverter):
    SQLA_TYPE_MAPPING = {
        **BaseModelConverter.SQLA_TYPE_MAPPING,
        **{GeometryType: fields.Field()},
    }


class EstateSchema(ma.ModelSchema):
    class Meta:
        model = Estates
        model_converter = ModelConverter

The same has been mentioned in the github repository of marshmallow-sqlalchemy

Related