I have two related object models that I am attempting to return through a marshmallow schema by using pluck. The primary model is a Product with a related field "technology_pillar" joined on a foreign key that should always return. In the schema definition I am using Pluck as described in the documentation but when I return it, I get TypeError: Object of type TechnologyPillar is not JSON serializable
. I'm stumped.
Models
from datetime import datetime
from typing import List
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class TechnologyPillar(db.Model):
__tablename__ = "product_technology_pillars"
id: db.Mapped[int] = db.mapped_column(primary_key=True)
technology_pillar: db.Mapped[str] = db.mapped_column(db.String(150), nullable=False, unique=True)
active_record: db.Mapped[bool] = db.mapped_column(db.Boolean)
product: db.Mapped[List["Product"]] = db.relationship(back_populates="technology_pillar")
def __repr__(self) -> str:
return f"TechnologyPillar(id={self.id!r}, technology_pillar={self.technology_pillar!r})"
class Product(db.Model):
__tablename__ = "products"
id: db.Mapped[int] = db.mapped_column(primary_key=True)
name: db.Mapped[str] = db.mapped_column(db.String(150), nullable=False, unique=True)
fk_pillar_id = db.mapped_column(db.ForeignKey('product_technology_pillars.id'))
technology_pillar: db.Mapped["TechnologyPillar"] = db.relationship(back_populates="product", lazy='joined', innerjoin=True)
active_record: db.Mapped[bool] = db.mapped_column(db.Boolean, nullable=False)
created_date: db.Mapped[datetime] = db.mapped_column(db.DateTime, default=datetime.utcnow)
modified_date: db.Mapped[datetime] = db.mapped_column(db.DateTime, default=datetime.utcnow)
def __repr__(self) -> str:
return f"Product(" \
f"id={self.id!r}, name={self.name!r})"
Schemas
from flask_marshmallow import Marshmallow
ma = Marshmallow()
class TechnologyPillarSchema(ma.SQLAlchemyAutoSchema):
class Meta:
fields = ("id", "technology_pillar")
class ProductSchema(ma.SQLAlchemyAutoSchema):
class Meta:
technology_pillar = ma.Pluck(TechnologyPillarSchema, 'technology_pillar')
fields = ("id", "name", "technology_pillar")
main.py
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from products.models import Product, TechnologyPillar
from products.schemas import ProductSchema, TechnologyPillarSchema
app = Flask(__name__)
db = SQLAlchemy(app)
technology_pillar_schema = TechnologyPillarSchema()
technology_pillars_schema = TechnologyPillarSchema(many=True)
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
@app.route('/<id>', methods=['GET'])
def singleProduct(id):
stmt = db.select(Product).where(Product.id == id)
single_product = db.session.scalars(stmt).first()
return product_schema.jsonify(single_product)
I have tried removing the joins from the models, and using lazy joins. I've tried removing the technology pillar pluck from the schemas. I've tried nesting. I've tried removing the model returns as strings. Removing the technology_pillar from the response entirely will return a working json model with only the fields in the product table, but any inclusion of the technology_pillar breaks it.
After posting this I lucked into the answer while trying an alternate solution. The Pluck statement must be outside of the meta. The corrected working version is:
class ProductSchema(ma.SQLAlchemyAutoSchema):
technology_pillar = ma.Pluck(TechnologyPillarSchema, 'technology_pillar')
class Meta:
fields = ("id", "name", "technology_pillar")