【问题标题】:Flask + SQLAlchemy result to JSONFlask + SQLAlchemy 结果转 JSON
【发布时间】:2018-12-30 20:33:29
【问题描述】:

我是 Flask 和 SQLAlchemy 的新手,我花了很多时间尝试使用 Flask url(不是 flask_restful)让我的数据库查询呈现为 JSON。

我以为我可以使用 n0nSmoker/SQLAlchemy-serializer 让它工作。它使用一个简单的查询,使用这个语法选择我的 Trade SQLAlchemy 类:

trades = Trade.query.all()

我能够毫无问题地返回 trades.to_dict()。

但是因为我需要做一个group_by,我需要使用db.session.query(Trade, Trade.exchange, Trade.trader.......等更灵活的语法,这个方法停止工作了。

我看过检查系统等其他选项,但它似乎有点超出我的技能水平。另外,像 _asdict() 这样的一些方法似乎在行级别不可用。

我有点迷茫,不知道如何继续。任何帮助将不胜感激。

编辑:请求更多代码: 顶部app.py

from flask import Flask
from flask_restful import Resource, Api
from models import *
from flask_sqlalchemy import SQLAlchemy
from sqlathanor import FlaskBaseModel, initialize_flask_sqlathanor

app = Flask(__name__)
app.config.from_pyfile('config.py')

db = SQLAlchemy(model_class = FlaskBaseModel)
db = initialize_flask_sqlathanor(db)

class Trades(Resource):
    def get(self):
        return AllTrades()

api.add_resource(Trades,'/')


if __name__ == '__main__':
    app.run(host="0.0.0.0")

来自models.py

from app import db

class Trade(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    exchange = db.Column(db.String(255))
    trader = db.Column(db.String(255))
    symbol = db.Column(db.String(255))
    coin = db.Column(db.String(255))
    order_id = db.Column(db.String(255))
    price = db.Column(db.String(255))
    qty = db.Column(db.String(255))
    fee = db.Column(db.String(255))
    fee_currency = db.Column(db.String(255))
    order_time = db.Column(db.DateTime(timezone=False))
    side = db.Column(db.String(255))
    maker_taker = db.Column(db.String(255))


def AllTrades():
    #t = Trade
    # trades = db.session.query(
    #   t,
    #   t.exchange,
    #   t.trader,
    #   t.symbol,
    #   t.coin,
    #   db.func.sum(t.qty),
    #   db.func.sum(t.fee).label("fee"),
    #   t.fee_currency,
    #   t.order_id,
    #   t.order_time,
    #   t.maker_taker
    # ).group_by(t.order_id).all()

    trades = Trade.query.all()
    trades = trades.to_json()

    return trades

完整的堆栈跟踪

    Traceback (most recent call last):
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_restful/__init__.py", line 273, in error_router
    return original_handler(e)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/_compat.py", line 32, in reraise
    raise value.with_traceback(tb)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_restful/__init__.py", line 273, in error_router
    return original_handler(e)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/_compat.py", line 32, in reraise
    raise value.with_traceback(tb)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_restful/__init__.py", line 480, in wrapper
    resp = resource(*args, **kwargs)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_restful/__init__.py", line 595, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Users/foo/Sites/Reporting_dev/app.py", line 18, in get
    return AllTrades()
  File "/Users/foo/Sites/Reporting_dev/models.py", line 42, in AllTrades
    trades = Trade.query.all()
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 514, in __get__
    return type.query_class(mapper, session=self.sa.session())
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/sqlalchemy/orm/scoping.py", line 74, in __call__
    return self.registry()
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 1001, in __call__
    return self.registry.setdefault(key, self.createfunc())
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2939, in __call__
    return self.class_(**local_kw)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 143, in __init__
    bind = options.pop('bind', None) or db.engine
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 877, in engine
    return self.get_engine()
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 887, in get_engine
    state = get_state(app)
  File "/Users/foo/anaconda3/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 570, in get_state
    'The sqlalchemy extension was not registered to the current ' \
AssertionError: The sqlalchemy extension was not registered to the current application.  Please make sure to call init_app() first.

【问题讨论】:

  • 我最近阅读了this 对另一个类似问题的回答。我没有使用过这个库,但我想我会提请你注意,因为它可能会有所帮助。
  • 除了我链接的答案之外,该问题中还有很多关于结果序列化的讨论。
  • 我为此使用了Flask-Marshmallow,效果非常好。这是一个我用过的简单项目 - github.com/tim-thompson/bonsai-trees

标签: python json flask sqlalchemy


【解决方案1】:

我建议你看看我在一两周前发布的一个名为 SQLAthanor 的新库。

它为 SQLAlchemy 模型添加了简单的序列化支持,如果您也在使用 Flask-SQLAlchemy,它也可以与它无缝协作。

基本上,它的工作方式是这样的:

  1. 你定义你的 Trade 模型的方式是你(大概)已经在做的。唯一的区别是您从 SQLAthanor 而不是从 SQLAlchemy(或 Flask-SQLAlchemy)导入 declarative_base 或基础模型。

  2. 在定义模型时配置序列化规则。这基本上可以让您说“当我将交易序列化为 JSON 时,包括属性 X、Y 和 Z,但不包括 P、D 和 Q”。

  3. 按照您通常的方式执行查询。你会得到一个Trade 实例的列表,大概。您现在可以通过调用 <instance>.to_json() 将每个实例序列化为 JSON。

值得一提的是SQLAthanor:

  • 支持序列化和反序列化到/从 JSON、CSV、YAML 和 Python dict
  • 支持Column 属性、关系、混合属性、关联代理和常规 Python @properties 的序列化/反序列化
  • 支持在属性级别进行序列化/反序列化的自定义前/后处理功能(用于验证或类型强制)
  • 支持在特定格式的属性级别启用/禁用序列化和反序列化(例如,接受入站密码,但从不包含出站密码)

可能值得一看。这是(我希望是全面的)文档的链接:http://sqlathanor.readthedocs.io/en/latest/

希望这会有所帮助,如果您有任何问题或需要帮助以使其正常运行,请告诉我(或使用标签sqlathanor 向 SO 发布问题)

【讨论】:

  • 确认!看起来像文档中的错字。您要导入/使用的函数是initialize_flask_sqlathanor 而不是initialize_sqlathanor。很抱歉造成混淆 - 我将在下一个补丁版本中修复文档(可能在今天晚些时候)。
  • 别担心!祝你好运,如果遇到麻烦,请告诉我。
  • 你能发布更完整的堆栈跟踪吗?此外,如果您发布了用于初始化 Flask-SQLAlchemy 和初始化 SQLAthanor 的代码,这将很有帮助。这将帮助我们确定问题是否发生在您正在初始化 SQLAthanor 的位置,或者它是否在您的其他地方应用程序(例如,Flask-SQLAlchemy 正在初始化的地方)。
  • 明白了。我相信这个问题首先与你如何初始化db 有关。使用您正在使用的初始化模式,您需要使用:db = SQLAlchemy(app, model_class = FlaskBaseModel)。这将在您的 Flask 应用程序中注册 Flask-SQLAlchemy。欲了解更多信息,请查看:flask-sqlalchemy.pocoo.org/2.3/quickstart
  • 另外,在今天的(重要的)新版本中,我更新了 SQLAthanor 的文档以显示您正在使用的更完整的模式。
猜你喜欢
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 2018-08-30
  • 1970-01-01
  • 2018-12-16
  • 2020-05-06
相关资源
最近更新 更多