【问题标题】:flask -- change output from responseflask -- 改变响应的输出
【发布时间】:2020-11-11 17:43:53
【问题描述】:

我正在尝试制作一个烧瓶 api(这对我来说是新领域),但我对返回数据的方式不满意。

它可以工作并连接到数据库并返回数据(耶),但它是一个字典列表(嘘)。

我想重新格式化它,所以当它被调用时,它看起来会有所不同。

烧瓶型号:

from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse, abort, fields, marshal_with
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
api = Api(app)
app.config["SQLALCHEMY_DATABASE_URI"] = 'postgres://postgres:[password]@127.0.0.1:5432/usagestats'
db = SQLAlchemy(app)

class StatsModel(db.Model):
    #added in from edit1
    def __getitem__(self, key):
        return self.__dict__[key]
    __tablename__ = "smogon_usage_stats"

    id_ = db.Column(db.Integer, primary_key=True)
    rank = db.Column(db.Integer, nullable=False)
    pokemon = db.Column(db.String(50), nullable=False)
    usage_pct = db.Column(db.Float, nullable=False)
    raw_usage = db.Column(db.Integer, nullable=False)
    raw_pct = db.Column(db.Float, nullable=False)
    real = db.Column(db.Integer, nullable=False)
    real_pct = db.Column(db.Float, nullable=False)
    dex = db.Column(db.Integer, nullable=False)
    date = db.Column(db.String(10), nullable=False)
    tier = db.Column(db.String(50), nullable=False)
    
    def __repr__(self):
        return f"Stats(id = {id_}, rank = {rank}, pokemon = {pokemon}, usage_pct = {usage_pct}, raw_usage = {raw_usage}, raw_pct = {raw_pct}, real = {real}, real_pct = {real_pct})"

resource_fields = {
    'id_': fields.Integer,
    'rank': fields.Integer,
    'pokemon': fields.String,
    'usage_pct': fields.Float,
    'raw_usage': fields.Integer,
    'raw_pct': fields.Float,
    'real': fields.Integer,
    'real_pct': fields.Float,
    'dex': fields.Integer,
    'date': fields.String,
    'tier': fields.String
}

class Stats(Resource):
    @marshal_with(resource_fields)
    def get(self, date, tier):
        result = StatsModel.query.filter_by(date=date, tier=tier + "-1500").all()

        return result

api.add_resource(Stats, "/stats/<string:date>/<string:tier>-1500")
if __name__ == "__main__":
    app.run(host='127.0.0.1', port=3000, debug=True)

调用时返回如下:

[
  {'id_': 669551, 'rank': 153, 'pokemon': 'snorunt', 'usage_pct': 0.07347, 'raw_usage': 104, 'raw_pct': 0.127, 'real': 96, 'real_pct': 0.148, 'dex': 361, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
  {'id_': 669552, 'rank': 154, 'pokemon': 'milcery', 'usage_pct': 0.0672, 'raw_usage': 108, 'raw_pct': 0.131, 'real': 87, 'real_pct': 0.134, 'dex': 868, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
  {'id_': 669553, 'rank': 156, 'pokemon': 'cosmog', 'usage_pct': 0.0199, 'raw_usage': 26, 'raw_pct': 0.032, 'real': 19, 'real_pct': 0.029, 'dex': 789, 'date': '2020-04', 'tier': 'gen8lc-1500'}
]

但我希望它看起来像这样:


{
  "data": 
    'snorunt': {
      'id_': 669551, 'rank': 153, 'pokemon': 'snorunt', 'usage_pct': 0.07347, 'raw_usage': 104, 'raw_pct': 0.127, 'real': 96, 'real_pct': 0.148, 'dex': 361, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
    'milcery': {
      'id_': 669552, 'rank': 154, 'pokemon': 'milcery', 'usage_pct': 0.0672, 'raw_usage': 108, 'raw_pct': 0.131, 'real': 87, 'real_pct': 0.134, 'dex': 868, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
    'cosmog': {
      'id_': 669553, 'rank': 156, 'pokemon': 'cosmog', 'usage_pct': 0.0199, 'raw_usage': 26, 'raw_pct': 0.032, 'real': 19, 'real_pct': 0.029, 'dex': 789, 'date': '2020-04', 'tier': 'gen8lc-1500'
  }
}

我尝试在Stats 类中操作result,但它会引发错误(我已经将其取出,但这是不可迭代的错误)。我想我总是可以用我的 webapp 代码更改数据,但我宁愿把它打包并准备好。

编辑 1

所以我找到了一些解决方案,但还没有什么效果。

为了使对象可下标,我将其添加到模型中:

    def __getitem__(self, key):
        return self.__dict__[key]
    __tablename__ = "smogon_usage_stats"

并制作了Stats类的get函数返回语句:

return {"data": {x["pokemon"]: x for x in result}}

但这只给了我一个输出。我猜这是技术上的改进。 (在尝试以下建议的答案时也得到了相同的结果

编辑 2

如果我可能遗漏了某些东西并且不再尝试对一行进行花哨,我尝试简化它,它仍然给我一个单一的输出。我已经验证result 是一个长度为143 的列表。但由于某种原因,我没有得到我想要的结果,而且我的空域和想法都用完了。

class Stats(Resource):
    @marshal_with(resource_fields)
    def get(self, date, tier):
        result = StatsModel.query.filter_by(date=date, tier=tier + "-1500").all()
        resp = {"data":{}}
        for i in range(len(result)): 
            t = {result[i]["pokemon"]: result[i]}
            resp["data"].update(t)
        return resp

当我发出请求时会返回这个:

{
'id_': 0, 
'rank': 0, 
'pokemon': None, 
'usage_pct': None, 
#... to save space but you get the idea
'tier': None
}

另外,为了确定,我对迭代对象进行了type() 检查,它们返回了&lt;class '__main__.StatsModel'&gt;

【问题讨论】:

    标签: python json flask request flask-sqlalchemy


    【解决方案1】:

    我不确定这是否是最好的方法,但它的工作方式如您所愿。

    class Stats(Resource):
        @marshal_with(resource_fields)
        def get(self, date, tier):
            result = StatsModel.query.filter_by(date=date, tier=tier + "-1500").all()
    
            return {"data": list(map(lambda x: {x['pokemon']: x}, result))}
    

    【讨论】:

    • 不幸的是它没有用。我收到一个错误TypeError: 'StatsModel' object is not iterable
    【解决方案2】:

    试试这个。这将从您的结果中读取每个元素并将其保存到字典中。然后根据您的格式将此字典保存到另一个字典中:

    class Stats(Resource):
        @marshal_with(resource_fields)
        def get(self, date, tier):
            dict1, dict2 = {}, {}
            #result = StatsModel.query.filter_by(date=date, tier=tier + "-1500").all()
            for x in StatsModel.query.filter_by(date=date, tier=tier + "-1500").all():
                dict1[x["pokemon"]] = x.__dict__
            dict2["data"] = dict1
            return dict2
    

    【讨论】:

    • 感谢您的回复,但还是不行。我不确定发生了什么事。我已经通过打印 dict[key] 值进行了测试,并且它们打印出来了,所以它的功能就像字典一样。这是它给我的输出 {'id_': 0, 'rank': 0, 'pokemon': None, 'usage_pct': None, 'raw_usage': 0, 'raw_pct': None, 'real': 0, 'real_pct': None, 'dex': 0, 'date': None, 'tier': None} 并且没有给出错误。
    • 好的,您可以粘贴运行我提到的代码时收到的输出吗?
    • 对不起,我之前的评论令人困惑,这是我尝试使用您的解决方案时产生的。
    • 好的。你能说出结果的数据类型是什么吗?试试type(result)
    • type(result) 给了我&lt;class 'list'&gt; 并且result 中每个项目的type&lt;class '__main__.StatsModel'&gt;
    【解决方案3】:

    我没有使用过 Flask-RESTful,但这似乎是一个简单的数据转换问题。

    在交互式 Python shell 中:

    >>> rowList = [
    ...   {'id_': 669551, 'rank': 153, 'pokemon': 'snorunt', 'usage_pct': 0.07347, 'raw_usage': 104, 'raw_pct': 0.127, 'real': 96, 'real_pct': 0.148, 'dex': 361, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
    ...   {'id_': 669552, 'rank': 154, 'pokemon': 'milcery', 'usage_pct': 0.0672, 'raw_usage': 108, 'raw_pct': 0.131, 'real': 87, 'real_pct': 0.134, 'dex': 868, 'date': '2020-04', 'tier': 'gen8lc-1500'}, 
    ...   {'id_': 669553, 'rank': 156, 'pokemon': 'cosmog', 'usage_pct': 0.0199, 'raw_usage': 26, 'raw_pct': 0.032, 'real': 19, 'real_pct': 0.029, 'dex': 789, 'date': '2020-04', 'tier': 'gen8lc-1500'}
    ... ]
    >>> 
    >>> transformed = {"data": {row['pokemon']: row for row in rowList}}
    >>> 
    >>> import pprint
    >>> pprint.pprint(transformed)
    {'data': {'cosmog': {'date': '2020-04',
                         'dex': 789,
                         'id_': 669553,
                         'pokemon': 'cosmog',
                         'rank': 156,
                         'raw_pct': 0.032,
                         'raw_usage': 26,
                         'real': 19,
                         'real_pct': 0.029,
                         'tier': 'gen8lc-1500',
                         'usage_pct': 0.0199},
              'milcery': {'date': '2020-04',
                          'dex': 868,
                          'id_': 669552,
                          'pokemon': 'milcery',
                          'rank': 154,
                          'raw_pct': 0.131,
                          'raw_usage': 108,
                          'real': 87,
                          'real_pct': 0.134,
                          'tier': 'gen8lc-1500',
                          'usage_pct': 0.0672},
              'snorunt': {'date': '2020-04',
                          'dex': 361,
                          'id_': 669551,
                          'pokemon': 'snorunt',
                          'rank': 153,
                          'raw_pct': 0.127,
                          'raw_usage': 104,
                          'real': 96,
                          'real_pct': 0.148,
                          'tier': 'gen8lc-1500',
                          'usage_pct': 0.07347}}}
    >>> 
    

    除非我遗漏了什么,否则transformed 似乎正是您要找的。 (我错过了什么?)

    当然,您的代码中的result 可能不是list,而上面的rowList 是。在这种情况下,请考虑先将其转换为列表(并将包含的记录转换为字典)。

    【讨论】:

      【解决方案4】:

      为了简单的改变

      [
          {"id_": 669551, "rank": 153, "pokemon": "snorunt", "usage_pct": 0.07347, 
           "raw_usage": 104, "raw_pct": 0.127, "real": 96, "real_pct": 0.148, 
           "dex": 361, "date": "2020-04", "tier": "gen8lc-1500"},
          {"id_": 669552, "rank": 154, "pokemon": "milcery", "usage_pct": 0.0672,
           "raw_usage": 108, "raw_pct": 0.131, "real": 87, "real_pct": 0.134,
           "dex": 868, "date": "2020-04", "tier": "gen8lc-1500"},
          {"id_": 669553, "rank": 156, "pokemon": "cosmog", "usage_pct": 0.0199, 
           "raw_usage": 26, "raw_pct": 0.032, "real": 19, "real_pct": 0.029, 
           "dex": 789, "date": "2020-04", "tier": "gen8lc-1500"}
      ]
      

      {"data": {
          "snorunt": {
              "id_": 669551, "rank": 153, "pokemon": "snorunt", "usage_pct": 0.07347,
              "raw_usage": 104, "raw_pct": 0.127, "real": 96, "real_pct": 0.148, 
              "dex": 361, "date": "2020-04", "tier": "gen8lc-1500"},
          "milcery": {
              "id_": 669552, "rank": 154, "pokemon": "milcery", "usage_pct": 0.0672, 
              "raw_usage": 108, "raw_pct": 0.131, "real": 87, "real_pct": 0.134,
              "dex": 868, "date": "2020-04", "tier": "gen8lc-1500"},
          "cosmog": {
              "id_": 669553, "rank": 156, "pokemon": "cosmog", "usage_pct": 0.0199, 
              "raw_usage": 26, "raw_pct": 0.032, "real": 19, "real_pct": 0.029, 
              "dex": 789, "date": "2020-04", "tier": "gen8lc-1500"
          }
      }}
      

      简单尝试

      new_result = {"data": {}}
      for item in dictionary:
          new_result["data"][item["pokemon"]] = item
      

      其中dictionary 是第一个,new_result 是第二个。

      【讨论】:

        【解决方案5】:
        class Stats(Resource):
        @marshal_with(resource_fields)
        def get(self, date, tier):
            data_dict, result = {}, {}
            for item in StatsModel.query.filter_by(date=date, tier=tier + "-1500").all():
                data_dict[item["pokemon"]] = item
            result["data"] = data_dict
            return result
        

        【讨论】:

          猜你喜欢
          • 2012-05-25
          • 2013-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-01
          • 2020-08-29
          • 1970-01-01
          相关资源
          最近更新 更多