【问题标题】:Flask-marshmallow dump of flask-sqlalchemy outer join returns emptyflask-sqlalchemy 外连接的 Flask-marshmallow 转储返回空
【发布时间】:2020-07-30 19:27:21
【问题描述】:

我有两个表,PackMatData 和 ColorData:

class PackMatData(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    unique_name = db.Column(db.String(20), index=True, unique=True)
    se_name = db.Column(db.String(20), index=True)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    labflex_name = db.Column(db.String(20))
    country = db.Column(db.String(20), index=True)
    color_measurements = db.relationship('ColorData', backref='entry', cascade="all, delete-orphan", lazy='dynamic')


class ColorData(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    color = db.Column(db.String(20), index=True)
    patch = db.Column(db.String(10), index=True)
    L = db.Column(db.String(10), index=True)
    a = db.Column(db.String(10), index=True)
    b = db.Column(db.String(10), index=True)
    pack_mat_data_id = db.Column(db.Integer, db.ForeignKey('pack_mat_data.id'))

我想加入这些表,然后序列化返回值。我正在使用 flask-sqlalchemy 左外连接对 PackMatData 表的 id 执行连接:

@app.route('/api/entries')
def entries():

    pmcd = db.session.query(PackMatData, ColorData).outerjoin(ColorData, PackMatData.id == ColorData.pack_mat_data_id).all()
    data = [{"packmatdata": x[0], "colordata": x[1]} for x in pmcd]
    output = NestedSchema(many=True).dump(data)
    return jsonify(output)

从联接中,我以元组列表的形式获得了我期望的数据:

[...,(<PackMatData 138>, <ColorData 7272>), (<PackMatData 138>, <ColorData 7285>),(<PackMatData 138>, <ColorData 7286>), (<PackMatData 138>, <ColorData 7287>), (<PackMatData 138>, <ColorData 7284>), (<PackMatData 138>, <ColorData 7283>), (<PackMatData 139>, <ColorData 7321>), (<PackMatData 139>, <ColorData 7322>), (<PackMatData 139>, <ColorData 7323>), (<PackMatData 139>, <ColorData 7320>), (<PackMatData 139>, <ColorData 7319>), (<PackMatData 139>, <ColorData 7311>), ...]

我在 stackoverflow flask-marshmallow two db objects in one schema 中读到,marshmallow 需要一个字典列表,这就是为什么我在将它传递给转储之前进行转换。

这是我为序列化定义的模式:

class ColorDataSchema(ma.ModelSchema):
    class Meta:
        model = ColorData

class PackMatDataSchema(ma.ModelSchema):  
    class Meta:
        model = PackMatData

class NestedSchema(ma.ModelSchema):  
    colordata = ma.Nested(ColorDataSchema)
    packmatdata = ma.Nested(PackMatDataSchema, many=True)

问题是转储函数总是返回以下内容:

[...,{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},...]

我也尝试过这个模式(结果相同):

class PackMatDataSchema(ma.ModelSchema):  
    class Meta:
        model = PackMatData

class ColorDataSchema(ma.ModelSchema):
    packmatdata = ma.Nested(PackMatDataSchema, many=True)
    class Meta:
        model = ColorData

你能引导我走向正确的方向吗?很抱歉,这篇文章很长,但我想尽可能多地为您提供详细信息。

【问题讨论】:

  • 您找到解决方案了吗?我已经为同样的问题浪费了很多时间:(
  • 不,很遗憾我从未找到解决方案。我最终彻底改造了它
  • 与此同时,我发现如果您避免使用元组(连接表的结果),它会起作用,请在此处查看我的答案:stackoverflow.com/questions/67213618/… 我仍然不确定,如果它是最好的解决方案,因为它似乎不是很快(只是我的印象)。你是怎么解决的?

标签: python flask-sqlalchemy json-deserialization outer-join flask-marshmallow


【解决方案1】:

Marshmallow dump(many=True) 函数处理项目列表。它不能处理项目元组的列表。 该项目可以是对象或dict

L1 = [item1, item2, item3]
schema.dump(L1, many=True)
# returns [data1, data2, data3]

这里有一个项目链接到数据库中的另一个项目。

PackMatData 表: |编号 |唯一名称 | | -- | ------| | 1 |名称1 | | 2 |名称2 |

ColorData 表: |编号 |颜色 | pack_mat_data_id | | -- | ------| ---------------- | | 1 |颜色1 | 1 | | 2 |颜色2 | 1 | | 3 |颜色3 | 2 |

您需要向 Marshmallow 指定如何处理它。

#output type 1 : dumping PackMatData items
[
  { 
    id: 1,
    unique_name: name1, 
    color_measurements: [{id: 1, color: color1}, {id: 2, color: color2}],
  },
  {
    id: 2,
    unique_name: name2, 
    color_measurements: [{id: 3, color: color3}],
  }
]

#output type 2 : dumping ColorData items
[
  { 
    id: 1,
    color: color1, 
    entries: {id: 1, unique_name: name1},
  },
  {
    id: 2,
    color: color2, 
    entry: {id: 1, unique_name: name1},
  },
  { 
    id: 3,
    color: color3, 
    entry: {id: 2, unique_name: name2},
  },
]

#output type 3: dumping PackMatData and ColorData "side by side"
[
  { 
    packMetaData: {id:1, unique_name: name1},
    colorData: {id: 1, color: color1}
  },
  {
    packMetaData: {id:1, unique_name: name1},
    colorData: {id: 2, color: color2}
  },
  { 
    packMetaData: {id:2, unique_name: name2},
    colorData: {id: 3, color: color3}
  },
]

获取输出类型 1

class ColorDataSchema(ma.ModelSchema):
    class Meta:
        model = ColorData
    fields = ('id', 'color')  

class PackMatDataSchema(ma.ModelSchema):  
    class Meta:
        model = PackMatData
    color_measurements = fields.Nested(ColorDataSchema) #the name is important

query = db.session.query(PackMatData).all()
data = PackMatDataSchema().dump(query, many=True)

获取输出类型 2

class PackMatDataSchema(ma.ModelSchema):  
    class Meta:
        model = PackMatData

class ColorDataSchema(ma.ModelSchema):
    class Meta:
        model = ColorData
    entry = fields.Nested(PackMatDataSchema) #the name is important 

query = db.session.query(ColorData).all()
data = ColorDataSchema().dump(query, many=True)

并获得输出类型 3

class PackMatDataSchema(ma.ModelSchema):  
    class Meta:
        model = PackMatData

class ColorDataSchema(ma.ModelSchema):
    class Meta:
        model = ColorData
    fields = ('id', 'color')

class SideBySideSchema(ma.ModelSchema):
    packMetaData = fields.Nested(PackMatDataSchema)
    colorData = fields.Nested(ColorDataSchema)

query = db.session.query(PackMatData, ColorData).join(ColorData).all()
list_of_dict = [{packMetaData: p, colorData: c} for p, c in query]
data = SideBySideSchema().dump(list_of_dict, many=True)

【讨论】:

    【解决方案2】:

    这对我使用 flask-sqlalchemy、flask-marshmallow 和 marshmallow-sqlalchemy 很有用。

    也许,您需要将表名包含到您的烧瓶 SQL Alchemy 数据库模型中。

    class PackMatData(db.Model):
        __tablename__ = 'packmatdata'
        id = db.Column(db.Integer, primary_key=True)
        unique_name = db.Column(db.String(20), index=True, unique=True)
        se_name = db.Column(db.String(20), index=True)
        timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
        labflex_name = db.Column(db.String(20))
        country = db.Column(db.String(20), index=True)
        color_measurements = db.relationship('ColorData', backref='entry', cascade="all, delete-orphan", lazy='dynamic')
    
    
    class ColorData(db.Model):
        __tablename__ = 'colordata'
        id = db.Column(db.Integer, primary_key=True)
        color = db.Column(db.String(20), index=True)
        patch = db.Column(db.String(10), index=True)
        L = db.Column(db.String(10), index=True)
        a = db.Column(db.String(10), index=True)
        b = db.Column(db.String(10), index=True)
        pack_mat_data_id = db.Column(db.Integer, db.ForeignKey('pack_mat_data.id'))
    

    我在模式类中加入了一些额外的东西。这对您来说可能不是必需的。

    class PackMatDataSchema(ma.SQLAlchemyAutoSchema):  
        class Meta:
            model = PackMatData
            load_instance = True
    
    class ColorDataSchema(ma.SQLAlchemyAutoSchema):
        class Meta:
            model = ColorData
            load_instance = True
            include_fk = True
    

    为了反序列化 SQL Alchemy 查询,我使用了动态模式。 (我的情况需要动态模式。)

    @app.route('/api/entries')
    def entries():
        # SQL Alchemy automatically joins on foreign keys.
        pmcd = db.session.query(PackMatData, ColorData)\
            .outerjoin(ColorData).all()
        data = [
            {PackMatData.__tablename__: x[0],
             ColorData.__tablename__: x[1]} 
            for x in pmcd
            ]
        DynamicSchema = ma.Schema.from_dict({
            PackMatData.__tablename__: 
                ma.Nested(PackMatDataSchema, dump_only=True),
            ColorData.__tablename__: 
                ma.Nested(ColorDataSchema, dump_only=True)
            })
        dynamic_schema = DynamicSchema(many=True)
        return jsonify(dynamic_schema.dump(data))
    

    这应该可行。您可以尝试创建“NestedSchema”而不是使用动态模式。如前所述,我需要为自己的目的使用动态模式。我认为这对您的目的没有必要。

    ?

    【讨论】:

      猜你喜欢
      • 2021-04-19
      • 2017-06-08
      • 1970-01-01
      • 2021-08-04
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 2019-10-01
      • 2022-07-03
      相关资源
      最近更新 更多