Flask: 将Python字典转换为JSON对象供客户端API使用

3 投票
1 回答
11080 浏览
提问于 2025-04-18 05:05

我需要从Flask的查询结果创建一个json对象,然后把这个json对象传递给路由,以便创建一个API。

在寻找一些简单的方法来从我的实例创建字典时,我发现了一个帖子,里面提到可以使用实例的内部字典,并在模型类中添加一个叫做'jsond'的方法。下面是带有这个自定义方法'jsond'的模型:

from app import db  
class Rest(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(100), unique = True)
    street = db.Column(db.Text)
    zipcd = db.Column(db.Integer)
    comments = db.relationship('Comment', backref='rest', lazy='dynamic')
    lat = db.Column(db.Float(6))
    lng = db.Column(db.Float(6))

    def __init__(self,name,street,zipcd):
        self.name = name
        self.street = street
        self.zipcd = zipcd

    def __repr__(self):
        return '{}'.format(self.name)

    def name_slug(self):
        return self.name

    def jsond(self):
        instDict = self.__dict__.copy()
        if instDict.has_key('_sa_instance_state'):
            del instDict['_sa_instance_state']
        return instDict

这是我的视图函数:

from app import app, db
from flask import render_template, flash, redirect, session, url_for, request, g,      jsonify, make_response
from flask.json import dumps
from flask.ext import restful 
from flask.ext.httpauth import HTTPBasicAuth
from models import Comment, Rest, Badge
from helper import make_badges, make_inspections, loc_query
import operator
auth = HTTPBasicAuth()

@app.route('/api',methods=['GET'])
def makeApi():

    ###Query Parameters###
    lim = request.args.get('limit', 10)
    off = request.args.get('offset', 0)
    loc = request.args.get('location', "39.94106,-75.173192")
    lat, lng = loc.split(",")
    radius = request.args.get('radius',2)

    query = loc_query(lat,lng,radius,off,lim)

    results = Rest.query.from_statement(query).all()


    rest_json = []
    for rest in results:
        rest_json.append(rest.jsond())

    return make_response(jsonify({'count':len(rest_json),'rests':rest_json}))

所以当我在Python的API命令行中运行查询时,可以成功创建一个包含所有字段的字典(使用自定义的jsond方法)。但是当我通过我的视图访问makeApi路由时,得到的json对象只有'id'字段:

rests: [
{
id: 28450
},
{
id: 28795
},
{
id: 30439
},
{
id: 29325
},
{
id: 29765
},
{
id: 29928
},
{
id: 30383
},
{
id: 29064
},
{
id: 29862
},
{
id: 28610
}
]
}

我已经转了好几个圈,几个小时过去了,还是不知道为什么视图的行为和Python API会不一样。也许是我在使用jsonify时做错了什么,但我觉得不是。

1 个回答

4

一般来说,把模型转成 JSON 的方法并不好:

  • self.__dict__ 里面可能会有很多没有文档说明的键
  • 列的类型:你不能直接把 relationship 和列的类型转成 JSON,特别是 datetime 类型的列。
  • 安全性:有时候你可能想隐藏一些字段(比如对不可信的用户使用你的 API 时)。

一个好的做法是创建一个方法,返回一个可以转成 JSON 的字典:

class Foo(db.Model):
    field1 = db.Column(...)
    field2 = db.Column(...)

    def as_dict(self):
        obj_d = {
            'field1': self.field1,
            'field2': self.field2,
            ...
        }
        return obj_d

然后在你的视图中:

foos = Foo.query.all()
results = [ foo.as_dict() for foo in foos ]

return jsonify({count: len(results), results: results)

根据你的应用,你可以让 as_dict 更聪明一点,把字段(特别是日期时间字段)转换成 JavaScript 更友好的格式,或者添加一些方便的字段,比如跟随某个关系。

撰写回答