FlaskSQLAlchemy ORM/GeoAlchemy2生成字典,最终生成JSON

2024-05-23 18:17:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Flask/SQLAlchemy创建一个包含地图的web应用程序,因此我自然使用PostGIS数据库。geom列需要一个ST_转换,我需要将此列和所有其他列转换为JSON。数据库的总体结构是:

from app import login, db
from datetime import datetime
from geoalchemy2 import Geometry
from time import time
from flask import current_app
from sqlalchemy import func

class Streets(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    street = db.Column(db.String(50))
    geom = db.Column(Geometry(geometry_type='LINESTRING'))

    def to_dict(self):
        data = {
            'id': self.id,
            'street': self.street,
            '_geom': func.ST_AsGeoJSON(func.ST_Transform(self.geom, 4326))
        }
    return data

我的api路由将此结果转换为api:

return jsonify(Streets.query.get_or_404(id).to_dict())

但我一直收到这个错误:NameError: name 'ST_AsGeoJSON' is not defined

我还尝试创建我的_geom值,如下所示:

^{pr2}$

错误消息是:TypeError: Object of type 'BaseQuery' is not JSON serializable

最后,我尝试了这样的api路径:

    data = Streets.to_dict(
        db.session.query(
            func.ST_AsGeoJSON(
                func.ST_Transform(
                    Streets.geom, 4326
                )
            )
        )
        .filter(Streets.id==id))

    return jsonify(data)

我得到了另一个错误: AttributeError: 'BaseQuery' object has no attribute 'id'

如果我在flask shell中运行此程序,则可以:

streets = db.session.query(
        Streets.id,
        Streets.street,
        func.ST_AsGeoJSON(func.ST_Transform(Streets.geom, 4326)))

如何执行ST_Transform并将JSON获取到api路由?在

更新

我在SQLALchemy文档中发现了这一点,这让我获得了一些进展:“orm.column_属性()可用于映射SQL表达式。所以我试着把这个添加到我的class Streets(db.Model)

coords = db.column_property(func.ST_AsGeoJSON(func.ST_Transform(geom, 4326)))

然后我将其添加到data中,如下所示:

def to_dict(self):
    data = {
        'id': self.id,
        'street': self.street,
        'coords': self.coords
        }
    return data

但现在我对我的结果进行了双重编码,一次编码为GeoJSON,然后我jsonify它:

return jsonify(Streets.query.get_or_404(id).to_dict())

所以我的api插入\的:

{"coords": "{\"type\":\"MultiLineString\",\"coordinates\":[[[-80.8357132798193,35.2260689001034],[-80.8347602582754,35.2252424284259]]]}"}

使用ST_AsText将其转换为文本:

{"coords": "MULTILINESTRING((-80.8357132798193 35.2260689001034,-80.8347602582754 35.2252424284259))"}

我想我已经接近这个更新了,但是有没有人建议用我数据库中其他字段的JSON获取正确的GeoJSON?在


Tags: tofromimportselfidstreetdbdata
1条回答
网友
1楼 · 发布于 2024-05-23 18:17:55

第一个错误

NameError: name 'ST_AsGeoJSON' is not defined

意味着您的示例代码不是您实际使用的代码。您忘了通过func访问它。在修复了这个问题之后,它也无法工作,因为您将混合SQL世界和Python世界。func.ST_AsGeoJSON(...)创建一个SQL函数表达式对象,该对象应该编译为SQL并在查询中发送到DB,而不是传递给jsonify()。在

第二个错误

^{pr2}$

应该有点明显。在

data['_geom'] = db.session.query(func.ST_AsGeoJSON(func.ST_Transform(self.geom, 4326)))

创建一个Query,以及一个过于宽泛的查询,因为您没有将其限制为获取当前对象的数据。Query对象不可JSON序列化。在

data = Streets.to_dict(db.session.query(...)...)

您将Query对象作为self传递给Streets.to_dict(),然后该对象尝试在中访问其id属性

'id': self.id,

它失败的原因很明显,即将一个不相关的对象作为实例传递给一个方法。在

column_property()方法生成双编码的JSON,因为SQLAlchemy默认情况下不希望ST_AsGeoJSON返回JSON,而是将其视为文本,而实际上它返回文本。尝试手动解码:

def to_dict(self):
    data = {
        'id': self.id,
        'street': self.street,
        'coords': json.loads(self.coords)
        }
    return data

相关问题 更多 >