LarsaSolidor
LarsaSolidor

Reputation: 133

Nested fields with mashmallow_sqlalchemy and flask_marshmallow

I am trying to get a nested serialized output, but all I get is the 'many' side of the many-to-one's table's primary key.

Expected output:

[{'part_numbers': 
                 {'part_number': '23103048', 'description': 'blue product'},
  'machines': 2,
  'percent_complete': 5.0,
  'serial_number': '001',
  'timestamp_created': 2020-03-12T15:4:23.135098},
 {'part_numbers': 
                 {'part_number': '44444009', 'description': 'red product'},
  'machines': 1,
  'percent_complete': 60.0,
  'serial_number': '002',
  'timestamp_created': '2020-03-12T15:44:23.135098'}]

Actual output:

[{'id': 3,
  'machines': 2,
  'percent_complete': 5.0,
  'serial_number': '001',
  'timestamp_created': 2020-03-12T15:4:23.135098},
 {'id': 1,
  'machines': 1,
  'percent_complete': 60.0,
  'serial_number': '0002',
  'timestamp_created': '2020-03-12T15:44:23.135098'}]

These are my files. I have tried adding part_numbers = ma.Nested(PartNumbers) to the Machine schema inside models.py, but it didn't change the result!

my_app
|--- my_app
     |--- \__init\__.py
     |--- models.py
     |--- views.py

models.py

from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema

db = SQLAlchemy()
ma = Marshmallow()

### Models ###

class Machine(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    serial_number = db.Column(db.Text, unique=True)
    percent_complete = db.Column(db.Float)
    part_number_id = db.Column(db.Integer, db.ForeignKey('PartNumbers.id'))
    timestamp_created = db.Column(db.DateTime, default=datetime.utcnow)

class PartNumbers(db.Model):
    __tablename__ = 'PartNumbers'

    id = db.Column(db.Integer, primary_key=True)
    part_number = db.Column(db.Text, unique=True)
    description = db.Column(db.Text)
    machines = db.relationship('Machines', backref='machines', lazy='dynamic')


### Schemas ###

class PartNumbersSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = PartNumbers
        include_fk = True

class MachineSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = Machines
        include_relationships = True

__init__.py

from flask import Flask
from .models import db, ma
from .views import my_app

app = Flask(__name__)
db.init_app(app)
ma.init_app(app)
app.register_blueprint(my_app)

views.py

from flask import Blueprint
from .models import db, Machines, MachineSchema, PartNumbers

my_app = Blueprint("my_app", __name__)

machines_schema = MachineSchema(many=True)

@my_app.route('/')
def home()
    machines = db.session.query(Machines).all()
    return machines_schema.dump(machines)

Upvotes: 0

Views: 1506

Answers (1)

above_c_level
above_c_level

Reputation: 3929

  1. Define part_number in the Machine class:

    class Machine(db.Model):
      id = db.Column(db.Integer, primary_key=True)
      serial_number = db.Column(db.Text, unique=True)
      percent_complete = db.Column(db.Float)
      part_number_id = db.Column(db.Integer, db.ForeignKey('PartNumbers.id'))
      timestamp_created = db.Column(db.DateTime, default=datetime.utcnow)
      part_numbers = db.relationship('PartNumbers')
    
  2. You have to define part_numbers in the MachineSchema explicitly:

    from marshmallow_sqlalchemy import fields
    class MachineSchema(SQLAlchemyAutoSchema):
      class Meta:
        model = Machines
      part_numbers = fields.Nested(PartNumbersSchema)
    

I assumed part_numbers is a single object (1:1 relationship). Otherwise, you have to add many=True to part_numbers.

More details: https://marshmallow.readthedocs.io/en/stable/nesting.html

[edited to incorporate correction in comment]

Upvotes: 1

Related Questions