Home > Net >  SQLAlchemy-Marshmallow how to serialize nested schema objects as a list of values
SQLAlchemy-Marshmallow how to serialize nested schema objects as a list of values

Time:10-03

I have spent the past few days learning how to serialize nested SQLAlchemy relationship models using marshmallow schemas, however, I am unable to find a way to achieve my desired result.

So far, I have been able to get a many-to-many relationship to print all levels using the following models and schema

class RecipeIngredient(db.Model):
    __tablename__ = 'recipe_ingredient'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    recipe_id = db.Column(db.Integer, db.ForeignKey('recipe.id'))
    ingredient_name = db.Column(db.String(64), db.ForeignKey('ingredient.name'))


class Recipe(db.Model):
    __tablename__ = 'recipe'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(64))
    desc = db.Column(db.String(256))
    ingredients = relationship("Ingredient", secondary="recipe_ingredient", backref="recipes")


class Ingredient(db.Model):
    __tablename__ = 'ingredient'
    name = db.Column(db.String(64), primary_key=True)


class RecipeSchema(Schema):
    class Meta:
        ordered = True

    id = fields.Int()
    title = fields.Str()
    desc = fields.Str()
    ingredients = fields.Nested('IngredientSchema', exclude=('recipes',), many=True)


class IngredientSchema(Schema):
    class Meta:
        ordered = True

    name = fields.Str()
    recipes = fields.Nested('RecipeSchema', exclude=('categories',), many=True)

Executing RecipeSchema().dump(recipe) will return the following

{
    "id": 1,
    "title": "Pancakes",
    "desc": "Tastes just like a yorkshire pudding!",
    "ingredients": [
      {
        "name": "Milk"
      },
      {
        "name": "Egg"
      },
      {
        "name": "Flour"
      }
    ]
  }

However, I am trying to get nested attributes like ingredients to display in a list containing values only, like this

{
    "id": 1,
    "title": "Pancakes",
    "desc": "Tastes just like a yorkshire pudding!",
    "ingredients": ["Milk", "Egg", "Flour"]
}

If anyone knows of any way to achieve this that would be great, I am not sure if there are ways of adding more details custom serialization within schemas - but any pointers will be appreciated!

CodePudding user response:

Oh I figured it out, it involved creating a custom Field class as explained in the docs here.

class IngredientName(fields.Field):
    def _serialize(self, value, attr, obj, **kwargs):
        if value is None:
            return ''
        return value.name

I then used this class in the recipe schema with the following line

ingredients = fields.List(IngredientName(), exclude=('recipes',), many=True)
  • Related