0

Since few days I am wondering how to make my Flask app return valid GeoJSON, here is what I got so far:

models.py

class Building(base):

    __tablename__ = 'buildings'

    id = Column(Integer, primary_key=True)
    district = Column(Unicode)
    address = Column(Unicode)
    name = Column(Unicode)
    building_type = Column(Unicode)
    mpoly = Column(Geometry('MULTIPOLYGON'))

    building = relationship("User")


# this part is done as answered here: https://stackoverflow.com/questions/41684512/cant-transform-geometry-to-geojson
    def building_to_dict(self):
        return mapping(shapely.wkb.loads(str(self.mpoly), True))
    
    def __str__(self):
        d = dict()
        d["id"] = self.id
        d["district"] = self.district
        d["address"] = self.address
        d["name"] = self.name
        d["building_type"] = self.building_type
        d["mpoly"] = self.building_to_dict()
        return shapely.dumps(d)

Now at main file I have following routing:

app.py

@app.route('/geojson')
def get_json():
    features = session.query(Building.mpoly.ST_AsGeoJSON()).all()
    return jsonify(features)

And here are my two problems:

1) Returned JSON-like response that looks like following: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[16.8933137,52.471446],...,]]]}" Is not proper GeoJSON. Features variable before jsonify looks this way: [('{"type":"MultiPolygon","coordinates":[[[[16.914159616,52.473822807],...,]]]}',)]

2) How my GeoAlchemy query should look like, to return not just geometry field, but others as well?

Any kind of hints or helps highly appreciated, thanks in advance!

BreadFish
  • 85
  • 1
  • 8
  • So I do not know the exact solution, but I think your Question is related to the following links. (1) https://stackoverflow.com/questions/7907596/json-dumps-vs-flask-jsonify . (2) https://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask . According to the comment in 1 flask jsonify "...does not turn SQLAlchemy objects and lists into JSON." So I believe what you might need to do is write a function or class that serializes the database object(features) , and then pass it to return jsonify(features). – Akib Rhast Jun 30 '20 at 21:00
  • [('{"type":"MultiPolygon","coordinates":[[[[16.914159616,52.473822807],...,]]]}',)] <-- That does not look like a json, but more like a set holding a string inside a list.. So look into serializing transforming that data into json. This is what pure GeoJson structure looks like : { "type": "Feature", "geometry": { "type": "Point", "coordinates": [125.6, 10.1] }, "properties": { "name": "Dinagat Islands" } } – Akib Rhast Jun 30 '20 at 21:03

1 Answers1

1

You may use marshmallow-sqlalchemy for creating json like responses.

create schemas.py

    #!schemas.py
    from marshmallow import fields
    from marshmallow_sqlalchemy import ModelSchema
    from app.models import Building
    from geoalchemy.shape import to_shape


    class BuildingSchema(ModelSchema):
        id = fields.Integer()
        district = fileds.Unicode()
        address = fileds.Unicode()
        name = fields.Unicode()
        building_type = fields.Unicode()
        mpoly = fileds.Method("geom_to_json")
    
        @staticmethod
        def geom_to_json(obj):
            mpoly = to_shape(obj.mpoly)
            return {
                    lat: mpoly.y,
                    lon: mpoly.x,
                    #and so on ... 
                    } 
        
        class Meta:
            model = Building
            exclude = ("mpoly")
            

    bulding_schema = BuildingSchema(many=True)
    

after this you can use it in your views(routes)

    from app.schemas import building_schema 


    @app.route('/geojson')
    def json():
        buildings = Buildings.query.all()
        response = building_schema.dumps(buildings)
        
        return response

James Nur
  • 23
  • 4