Результаты Flask-SQLAlchemy ORM / GeoAlchemy2 к словарю и в конечном итоге к JSON - PullRequest
0 голосов
/ 18 мая 2018

Я использую Flask / SQLAlchemy для создания веб-приложения с картой в нем, поэтому, естественно, я использую базу данных PostGIS.Столбец geom требует ST_Transform и каким-то образом мне нужно превратить этот столбец и все остальные в 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 следующим образом:

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

Сообщение об ошибке: 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, которая дала мне некоторыеprogress: «orm.column_property () можно использовать для сопоставления выражения 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 вставляет \ s:

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

И использование ST_AsText просто превращает его в текст:

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

Я думаю, что я близок к этому обновлению, но есть ли у кого-нибудь предложение для получения правильного GeoJSON с JSON других полей моей базы данных?

1 Ответ

0 голосов
/ 21 мая 2018

Первая ошибка

NameError: name 'ST_AsGeoJSON' is not defined

означает, что ваш пример кода не тот, который вы на самом деле использовали.Вы забыли получить к нему доступ через func.Это не сработает и после исправления, поскольку вы будете смешивать мир SQL и мир Python.func.ST_AsGeoJSON(...) создает объект выражения функции SQL, который должен быть скомпилирован в SQL и отправлен в БД в запросе, а не в jsonify().

Вторая ошибка

TypeError: Object of type 'BaseQuery' is not JSON serializable

должно быть несколько очевидным.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...