Marshmallow返回Geoalchemy2原始数据报WKBElement序列化错误
GeoAlchemy2读取数据库空间字段时,默认返回WKBElement类型的二进制封装对象,Python原生JSON序列化器无法识别这类自定义类型,直接通过fields.Raw()返回字段值时就会触发该类型错误。
另外你现有模型的__format_geolocation方法存在逻辑bug:判断条件if self.latitude or self.longitude == None不符合预期,只要latitude为非空真值就不会触发空值返回,正确写法应为if self.latitude is None or self.longitude is None,避免经纬度缺失时抛出异常。
你可以根据需求二选一:
方案1:自定义Marshmallow序列化字段,直接返回前端可用的结构化空间数据
实现自定义字段,自动完成WKBElement和前端常用GeoJSON格式的双向转换,不需要修改查询逻辑:from marshmallow import fields import geoalchemy2 as ga class GeoPointField(fields.Field): def _serialize(self, value, attr, obj, **kwargs): if not value: return None # 从WKBElement解析经纬度,返回标准GeoJSON点格式 point = ga.shape.to_shape(value) return { "type": "Point", "coordinates": [point.x, point.y], "srid": 4326 } def _deserialize(self, value, attr, data, **kwargs): if not value: return None # 接收前端传入的GeoJSON/经纬度对象,转成GeoAlchemy2支持的存储格式 lng, lat = value["coordinates"] return f"SRID=4326;POINT({lng} {lat})"替换原有Schema中的字段配置即可:
class LocationSchema(Schema): """ Location Schema """ geolocation = GeoPointField()该方案返回的是标准GeoJSON结构,所有主流前端地图库(Leaflet、Mapbox、OpenLayers等)都可以直接读取使用,无需额外解析。
方案2:查询阶段直接输出序列化后的空间字符串
如果你用的是PostgreSQL+PostGIS作为存储,可以在查询时直接调用PostGIS内置的ST_AsGeoJSON函数,直接在数据库层完成空间数据到JSON字符串的转换,不需要自定义Marshmallow字段:from sqlalchemy import func from geoalchemy2.functions import ST_AsGeoJSON # 查询示例 location_list = LocationModel.query.with_entities( LocationModel.id, # 其他需要返回的字段写在这里 ST_AsGeoJSON(LocationModel.geolocation).label("geolocation") ).all()这种场景下Schema中
geolocation字段直接用fields.Str()即可,前端拿到字符串后调用JSON.parse()就能得到可直接使用的空间对象。
内容的提问来源于stack exchange,提问作者cp-stack

