【问题标题】:Loading One to Many associated attribute with SQLalchemy and Marshmallow使用 SQLalchemy 和 Marshmallow 加载一对多关联属性
【发布时间】:2015-09-03 23:14:41
【问题描述】:

我正在构建一个烧瓶 api,我正在尝试学习如何从 1-n 关系中加载父模型的属性。

首先我加载所有库存物品。这很好用。我的目标是加载每个库存项目的父模型(材料)名称属性。

只是为了澄清问题,材料有许多库存物品。库存项目属于物料。我收集了所有库存物品。

我的目标是这样的:

{'id': 1, 'location': None, 'material_name': {'name': 'load name'}

但我从不加载名称,它返回空白:

{'id': 1, 'location': None, 'material_name': {'name': ''}

我正在使用 Marshmallow 创建一个 flask-api 并返回漂亮的 JSON。

这是我的model.py

from app import db
from marshmallow import Schema, fields

class Material(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), index=True, unique=False)
    items = db.relationship('Inventory', backref='material', lazy='dynamic')

class Inventory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    location = db.Column(db.Integer, primary_key=False)
    material_id = db.Column(db.Integer, db.ForeignKey('material.id'))
    def __init__(self, material_name):
        self.material_name = material_name

##### SCHEMAS (marshmallow) #####
# http://marshmallow.readthedocs.org/en/latest/examples.html

class MaterialSchema(Schema):
    id = fields.Int(dump_only=True)
    name = fields.Str()

class InventorySchema(Schema):
    id = fields.Int(dump_only=True)
    location = fields.Int(dump_only=True)
    material_name = fields.Nested(MaterialSchema, only=["name"])

和我的查询:

inventory_schema = InventorySchema(many=True)
@api.route('/api/inventory', methods=['GET'])
@cross_origin()
def inventoryindex():
    d=request.args['q']
    if len(d) >= 1:
        search_term = "%{0}%".format(d)
        count = Inventory.query.filter(Inventory.location.like(search_term)).count
        items = Inventory.query.filter(Inventory.location.like(search_term)).limit(10)
    else:
        count = Inventory.query.count()
        items = Inventory.query.limit(10)
    result = inventory_schema.dump(items)
    print(result)
    dictionary = {}
    for obj in result[0]:
        dictionary[obj['id']] = obj
    return jsonify({'dict':dictionary})

它返回我期望的所有内容,除了材质名称为空。如何从上面的库存查询中加载材料 ID?

【问题讨论】:

    标签: python flask sqlalchemy python-3.4 flask-sqlalchemy


    【解决方案1】:

    解决方案 1

    你为什么一开始就想要这样。 item['material_name']['name'] 看起来像是 name 的重复两次。

    IMO 最好的解决方案是将格式更改为:

    {'id': 1, 'location': None, 'material': {'name': 'load name'}
    

    您可以更改架构以加载材料名称:

    class InventorySchema(Schema):
        id = fields.Int(dump_only=True)
        location = fields.Int(dump_only=True)
        material = fields.Nested(MaterialSchema, only=["name"])
    

    解决方案 2

    如果您坚持要求格式,您可以更改 InventorySchema 以通过传递 attribute 参数从正确的属性中获取值:

    class InventorySchema(Schema):
        id = fields.Int(dump_only=True)
        location = fields.Int(dump_only=True)
        material_name = fields.Nested(MaterialSchema, attribute='material', only=["name"])
    

    【讨论】:

    • 这会触发 N+1 个查询来获取材料名称吗?
    • @pate 我不熟悉 Marshmallow 的内部结构,但很可能是的。要解决此问题,您可以覆盖查询以包含 .options(joinedload="material") 之类的内容。
    猜你喜欢
    • 2020-04-14
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2011-11-25
    • 2011-06-02
    相关资源
    最近更新 更多