烧瓶-从响应更改输出

时间:2020-11-11 17:43:53

标签: python json flask request flask-sqlalchemy

我要创建一个Flask API(对我来说这是新领域),我对返回数据的方式不满意。

它可以工作并连接到数据库并返回数据(是的),但这是词典列表(boo)。

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

烧瓶模型:

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'
  }
}

我尝试在result类中操作Stats,但是它引发了一个错误(我已经将其取出来了,但这是不可迭代的错误)。我想,我总是可以使用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()检查,它们返回了<class '__main__.StatsModel'>

5 个答案:

答案 0 :(得分:2)

我不确定这是否是最好的方法,但是它的工作方式与您想要的方式一样。

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))}

答案 1 :(得分:1)

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

import io
import base64
from PIL import Image

base64_str = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='

buffer = io.BytesIO()
imgdata = base64.b64decode(base64_str)
img = Image.open(io.BytesIO(imgdata))
new_img = img.resize((2, 2))  # x, y
new_img.save(buffer, format="PNG")
img_b64 = base64.b64encode(buffer.getvalue())
print(str(img_b64)[2:-1])

答案 2 :(得分:0)

我还没有使用过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是。在这种情况下,请考虑首先将其转换为列表(并将包含的记录转换为字典)。

答案 3 :(得分:0)

仅需在它们之间进行更改

[
    {"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是第二个。

答案 4 :(得分:0)

import React , {useState, useEffect} from 'react';
const [userData, setUserData] = useState({});

  useEffect(() => {
    const getUser = async () => {
      const response = await axios.get('api/babyinfo');
        setUserData(response.data.data[0]);
      }
      getUser();
    },[]);

   return <span>{userData.name}</span>