Flask-SQLAlchemy查询所有记录时如何正确返回JSON格式数据
问题原因
IncomeExpenseModel.query.all() 返回的是由多个IncomeExpenseModel实例组成的列表,不是单个模型对象,你直接对列表调用.orderdate、.who这类仅模型实例才有的属性,必然触发属性错误,导致接口无法正常返回JSON。
单条查询接口用get_or_404(id)拿到的是单个模型实例,所以可以直接读取属性构造返回字典,不存在这个问题。
另外你的模型中income、expense字段是Numeric类型,对应Python的Decimal类型,Flask默认的JSON序列化器不支持该类型,直接返回也会触发序列化报错,需要做类型转换。
修改方案
方案1:直接修改全量接口逻辑
遍历查询返回的对象列表,将每个模型实例手动转为可序列化的字典,同时处理Decimal类型的转换:
@app.route('/incomeexpense/all', methods=['GET']) def handle_incomexpense_all(): incomeexpense_list = IncomeExpenseModel.query.all() response_list = [] for item in incomeexpense_list: response_list.append({ "id": item.id, "orderdate": item.orderdate, "who": item.who, "location": item.location, "income": float(item.income) if item.income is not None else None, "expense": float(item.expense) if item.expense is not None else None }) return {"message": "success", "incomeexpense": response_list}
注:路由已经限定了仅接受GET请求,接口里的
request.method == 'GET'判断是冗余代码,可以直接删掉。
方案2:给模型添加序列化方法(推荐)
在模型类中新增统一的to_dict()序列化方法,单条、全量接口可以直接复用,避免重复写字段映射逻辑:
class IncomeExpenseModel(db.Model): __tablename__ = 'incomeexpense' id = db.Column(db.Integer, primary_key=True) orderdate = db.Column(db.String()) who = db.Column(db.String()) location = db.Column(db.Integer()) income = db.Column(db.Numeric(16,2), nullable=True) expense = db.Column(db.Numeric(16,2), nullable=True) def __init__(self, orderdate, who, location, income, expense): self.orderdate = orderdate self.who = who self.location = location self.income = income self.expense = expense # 新增统一序列化方法 def to_dict(self): return { "id": self.id, "orderdate": self.orderdate, "who": self.who, "location": self.location, "income": float(self.income) if self.income is not None else None, "expense": float(self.expense) if self.expense is not None else None }
修改后两个接口都可以大幅简化:
- 单条查询接口
@app.route('/incomeexpense/<id>', methods=['GET']) def handle_incomexpense(id): incomeexpense = IncomeExpenseModel.query.get_or_404(id) return {"message": "success", "incomeexpense": incomeexpense.to_dict()}
- 全量查询接口
@app.route('/incomeexpense/all', methods=['GET']) def handle_incomexpense_all(): incomeexpense_list = IncomeExpenseModel.query.all() response_list = [item.to_dict() for item in incomeexpense_list] return {"message": "success", "incomeexpense": response_list}
额外注意
Flask路由按照注册顺序匹配,固定路径/incomeexpense/all必须写在动态路径/incomeexpense/<id>的前面,否则框架会把路径中的all当成id参数传入单条查询接口,触发404错误。
内容的提问来源于stack exchange,提问作者Bernd
相关产品推荐
相关产品推荐

