python - 在 Marshallow/SQLAlchemy 架构上展平数据

标签 python flask sqlalchemy marshmallow

我在如何从端点之一取回数据方面遇到一些问题 - 特别是使用 Marshmallow 和 SQLAlchemy。

我在鸡尾酒和配料之间存在多对多关系,但我在关系表 ings_in_cocktail 上还拥有比外键更多的数据,例如盎司。 当我获取 /cocktails/,它返回如下内容:

{
  "cocktails": [
    {
      "glass": "rocks",
      "ingredients": [
        {
          "ingredient": {
            "ing_type": "liquor",
            "id": 1,
            "name": "gin"
          },
          "ounces": 20
        }
      ],
      "finish": "stirred",
      "id": 1,
      "name": "gin and tonic"
    }
  ]
}

我想做的是将 ounces 属性与 ingredient 字典结合起来。

我希望数据如下所示:

{
  "cocktails": [
    {
      "glass": "rocks",
      "ingredients": [
        {
          "ing_type": "liquor",
          "id": 1,
          "name": "gin",
          "ounces": 20
        }
      ],
      "finish": "stirred",
      "id": 1,
      "name": "gin and tonic"
    }
  ]
}

在网上搜索了几个小时后,我找不到使用 Marshmallow 轻松完成此操作的方法。我缺少一些简单的方法吗?

代码

配料.py

from flask import Flask
from settings import db, ma

class Ingredient(db.Model):
    __tablename__ = 'ingredients'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    ing_type = db.Column(db.String(20), nullable=False)

class IngredientSchema(ma.ModelSchema):
    class Meta:
        model = Ingredient

ings_in_cocktail.py

from flask import Flask
from settings import db, ma

from models.ingredients import Ingredient, IngredientSchema

class CocktailIngredient(db.Model):
    __tablename__ = 'ings_in_cocktail'
    ing_id = db.Column(db.Integer, db.ForeignKey('ingredients.id'), primary_key=True)
    cocktail_id = db.Column(db.Integer, db.ForeignKey('cocktails.id'), primary_key=True)
    ounces = db.Column(db.Integer, nullable=False)

    ingredient = db.relationship('Ingredient')

# Necessary for transforming sqlalchemy data into serialized JSON


class CocktailIngredientSchema(ma.ModelSchema):
    ingredient = ma.Nested(IngredientSchema, strict=True)

    class Meta:
    model = CocktailIngredient

cocktails.py

from flask import Flask
from settings import db, ma

from models.ing_in_cocktails import CocktailIngredient, CocktailIngredientSchema
from models.ingredients import Ingredient, IngredientSchema

class Cocktail(db.Model):
    __tablename__ = 'cocktails'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    glass = db.Column(db.String(20), nullable=False)
    finish = db.Column(db.String(20), nullable=True)
    ingredients = db.relationship(
        'CocktailIngredient',
        # secondary='ings_in_cocktail',
        backref=db.backref('cocktails'),
        # primaryjoin=id == CocktailIngredient.cocktail_id
    )

# Necessary for transforming sqlalchemy data into serialized JSON
class CocktailSchema(ma.ModelSchema):
    # this is responsible for returning all the ingredient data on the cocktail
    ingredients = ma.Nested(CocktailIngredientSchema, many=True, strict=True)
    class Meta:
    model = Cocktail

最佳答案

更新:我在底部放置了更好的解决方案。

您可以通过使用 Method 来实现此目的或Function允许父级从其子级获取数据的字段。这是您需要执行的操作:

  1. 离开 CocktailSchema独自的。
  2. 摆脱IngredientSchema完全(除非您还需要它来做其他事情)。
  3. 内部CocktailIngredientSchema ,替换 Nested领域有几个Function直接从内部“成分”对象中提取数据的字段。

之前的架构

class IngredientSchema(ma.ModelSchema):
    class Meta:
        model = Ingredient


class CocktailIngredientSchema(ma.ModelSchema):
    ingredient = ma.Nested(IngredientSchema)

    class Meta:
        model = CocktailIngredient


class CocktailSchema(ma.ModelSchema):
    ingredients = ma.Nested(CocktailIngredientSchema, many=True)

    class Meta:
        model = Cocktail

之后的架构

class CocktailIngredientSchema(ma.ModelSchema):
    ing_type = ma.Function(lambda obj: obj.ingredient.ing_type)
    id = ma.Function(lambda obj: obj.ingredient.id)
    name = ma.Function(lambda obj: obj.ingredient.name)

    class Meta:
        model = CocktailIngredient


class CocktailSchema(ma.ModelSchema):
    ingredients = ma.Nested(CocktailIngredientSchema, many=True)

    class Meta:
        model = Cocktail

棉花糖版本 3+ 的更干净的替代方案(需要 Python 3)

  1. 离开 CocktailSchema独自的。
  2. 离开 IngredientSchema单独(而不是如上所示摆脱它)。
  3. 内部CocktailIngredientSchema ,替换 Nested领域有几个Pluck直接从内部架构中提取数据的字段。

之后的架构

class IngredientSchema(ma.ModelSchema):
    class Meta:
        model = Ingredient


class CocktailIngredientSchema(ma.ModelSchema):
    ing_type = ma.Pluck(IngredientSchema, 'ing_type')
    id = ma.Pluck(IngredientSchema, 'id')
    name = ma.Pluck(IngredientSchema, 'name')

    class Meta:
        model = CocktailIngredient


class CocktailSchema(ma.ModelSchema):
    ingredients = ma.Nested(CocktailIngredientSchema, many=True)

    class Meta:
        model = Cocktail

关于python - 在 Marshallow/SQLAlchemy 架构上展平数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54174938/

相关文章:

python - 如何使用 SQLAlchemy 将一个类映射到多个表?

python - 使用 sqlalchemy 将 pandas 数据框插入 mysql

python - 删除python3中html标签之间的换行符

python - 使用 Pytest 测试 Flask session

python - 用于 selenium 浏览器自动化的 Flask Web 应用程序输入

python - 单元测试使用 Mock 4.0.0 生成 "RuntimeError: Working outside of application context."

python - 动态创建对象的 Doctest

java - 我怎样才能用Java编写这个Python代码(解析一串整数,使用分隔符)?

python - 如何检查列表中具有特定要求的所有元素?

Python:网页抓取标签导航 wiki 表