You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flask-Restplus中合并两张表数据返回单一API响应?

看起来你遇到的问题是因为Flask-Restplus的序列化逻辑把查询返回的(User, Device)元组里的两个对象分别处理了,所以才生成了重复的条目。咱们一步步来解决这个问题:

1. 先搞清楚问题根源

你当前的查询返回的是(User, Device)元组的列表,而@api.marshal_list_with(_details, envelope='data')会遍历这个列表里的每一个元素——也就是每个元组里的User和Device对象,分别用_details模型序列化,自然就出现了两条重复id/name但token不同的记录。

2. 方案一:手动合并查询结果(直观易理解)

我们可以先把查询到的User和Device字段合并成单个字典,再交给序列化器处理:

调整业务逻辑代码

在你的user(data=data)函数里,把查询结果转换成合并后的字典列表:

def user(data):
    details = db.session.query(User, Device).filter(User.id == Device.id)\
        .filter(User.email == data['email']).all()
    
    # 合并每个(User, Device)元组为一个符合DTO结构的字典
    combined_results = []
    for user_obj, device_obj in details:
        combined = {
            "id": user_obj.id,
            "name": user_obj.name,
            "token": device_obj.token if device_obj else None
        }
        combined_results.append(combined)
    
    # 如果需要你期望的双层数组结构,就返回[combined_results],否则直接返回combined_results
    return combined_results

保持现有DTO不变

你的_details模型已经完全匹配合并后的字典结构,所以控制器上的@api.marshal_list_with(_details, envelope='data')可以直接保留。

3. 方案二:利用Flask-Restplus的attribute参数(更简洁)

如果不想手动合并字典,可以修改DTO模型,指定每个字段对应的数据源路径:

定义新的合并输出模型

在UserDto里新增一个适配元组结构的模型:

class UserDto:
    # ... 原有input模型保持不变
    # 适配(User, Device)元组的输出模型
    combined_details = api.model('combined_details', {
        'id': fields.Integer(attribute='0.id', description='User的ID'),
        'name': fields.String(attribute='0.name', description='User的名称'),
        'token': fields.String(attribute='1.token', description='Device的Token')
    })

这里的'0.id'代表取元组第0个元素(User对象)的id属性,'1.token'代表取元组第1个元素(Device对象)的token属性。

修改控制器的序列化装饰器

把原来的@api.marshal_list_with(_details, envelope='data')换成:

@api.marshal_list_with(UserDto.combined_details, envelope='data')

这样序列化器会自动从元组里提取对应字段,直接生成你想要的结构。

4. 额外小提示

注意你的User模型里name字段定义成了db.Column(db.Integer),这大概率是个笔误——名称应该是字符串类型,建议修正为:

name = db.Column(db.String, unique=True, nullable=True)

调整完成后,你的API就能返回符合预期的响应了:

{
  "data": [
    {
      "id": 20,
      "name": null,
      "token": "Some String here"
    }
  ]
}

(如果确实需要你期望里的双层数组,只需要在返回结果时多包一层数组,比如return [combined_results]即可)

内容的提问来源于stack exchange,提问作者ken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:15:34