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)