Marshmallow: ValidationError: {'_schema': ['Invalid input type.']} for nested field, many=True

Created on 7 Mar 2019  Â·  6Comments  Â·  Source: marshmallow-code/marshmallow

Hello all, I am attempting to understand how marshmallow works. I am getting the above error
with the below code, and the below dataset

{'name': 'kay', 
  'id': 1
 'children': [
              {'name': 'Taylor', 'id': 1, 
                'toys': [
                  {'name': 'video game','id': 1 }
                  ]
               }, 
              {'name': 'Paige',  'id': 2, 
               'toys': [
                 {'name': 'baby', 'id': 1}
              ]
         }], 
}

the schemas are auto-generated by a superclass named BaseModel via classmethods and __init_subclass__, but look something like this:

class GeneratedSchema(Schema):
     class Meta:
         fields=[# auto generated from column keys if none, else from the class attribute "fields"]
         model= the class that BaseModel recieved
        strict=True
     # the nested field is only included if a relationship is detected
     "field_name"= fields.Nested(theNestedSchema,
     many= True if the Column's uselist=None or False 
     # this definition continues for all columns
     "other_fields" = the marshmallow field associated with the column's inner data type

Notes about the SQLAlchemy models,
The schema attribute grabs default and required attributes off the Column() Instance
if Column.nullable== false or Column.nullable is None, then required=True. Else required=False
if Column.default != None, then the value is taken from Column.default
if Column.uselist == None or True, then fields.Nested.many==True else fields.Nested.many==False
the schema is placed on each class under the name 'schema'

And the SQLAlchemy Models


class Toy(BaseModel):
    fields=['id','name']
    id=db.Column(db.Integer(), primary_key=True)
    child_id = db.Column(db.Integer, db.ForeignKey('child.id'))
    name = db.Column(db.String)

class Child(BaseModel):
    fields= ['id','name','toys']
    id=db.Column(db.Integer(), primary_key=True)
    parent_id= db.Column(db.Integer, db.ForeignKey('parent.id'))
    name = db.Column(db.String)
    toys = db.relationship('Toy')

class Parent(BaseModel):  
    id=db.Column(db.Integer(), primary_key=True)  
    name = db.Column(db.String)  
    children = db.relationship('Child')  


db.create_all()
if __name__ == "__main__":
    parent = 
    Parent(id=1,name='kay',
        child=Child(name='jordan'),
                    children=[
                        Child(id=1,name='Taylor',
                            toys=[
                                Toy(id=1,name='video game')
                            ]),
                        Child(id=2,name='Paige',
                             toys=[
                                 Toy(id=1,name='baby')
                             ])
                         ]
                    )
    db.session.add(parent)
    db.session.commit()   
    print( parent.schema.dump(parent))

Can anyone spot where my problem is?

I have also noticed that an Integer value of 0 for an Integer field shows as None when dumped with schema.dump.

question

Most helpful comment

The docs for marshmallow-sqlalchemy show how to overload relationships with nested fields.

https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#overriding-generated-fields

class ChildSchema(ma.ModelSchema):
    toys = ma.Nested(ToySchema, many=True)
    class Meta:
        model = Child


class ParentSchema(ma.ModelSchema):
    children = ma.Nested(ChildSchema, many=True)
    class Meta:
        model = Parent


db.create_all()
if __name__ == '__main__':
    schema = ParentSchema()
    data = {'name': 'kay', 
      'id': 1,
     'children': [
                  {'name': 'Taylor', 'id': 1, 
                    'toys': [
                      {'name': 'video game','id': 1 }
                      ]
                   }, 
                  {'name': 'Paige',  'id': 2, 
                   'toys': [
                     {'name': 'baby', 'id': 1}
                  ]
             }], 
    }
    print(schema.load(data).data)
    # <Parent (transient 4583120144)>

All 6 comments

Are you using marshmallow-sqlalchemy?

I am using flask-marshmallow, which in turn uses marshmallow-sqlalchemy

debug
ive attached some more data, hopefully it will help

from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'

db = SQLAlchemy(app)
ma = Marshmallow(app)

class Toy(db.Model):
    fields = ['id', 'name']
    id = db.Column(db.Integer(), primary_key=True)
    child_id = db.Column(db.Integer, db.ForeignKey('child.id'))
    name = db.Column(db.String)

class Child(db.Model):
    fields = ['id', 'name', 'toys']
    id = db.Column(db.Integer(), primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))
    name = db.Column(db.String)
    toys = db.relationship('Toy')

class Parent(db.Model):
    id = db.Column(db.Integer(), primary_key=True)  
    name = db.Column(db.String)
    children = db.relationship('Child')

class ToySchema(ma.ModelSchema):
    class Meta:
        model = Toy

class ChildSchema(ma.ModelSchema):
    class Meta:
        model = Child

class ParentSchema(ma.ModelSchema):
    class Meta:
        model = Parent


db.create_all()
if __name__ == '__main__':
    parent = Parent(
        name='kay',
        children=[
            Child(
                name='Taylor',
                toys=[Toy(name='video game')],
            ),
            Child(
                name='Paige',
                toys=[Toy(name='baby')],
            ),
        ],
    )
    db.session.add(parent)
    db.session.commit()   
    print(ParentSchema().dump(parent))

This example is working for me, so you might focus on debugging your BaseModel implementation.

Does that include nested fields in the schemas ? I’m defining nested fields on the schemas when a Relationship column is on the model class. The error only happens on load, not dump. Does that example validate data in nested columns?

Sent from my iPhone

On Mar 8, 2019, at 8:33 AM, Jared Deckard notifications@github.com wrote:

from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'

db = SQLAlchemy(app)
ma = Marshmallow(app)

class Toy(db.Model):
fields = ['id', 'name']
id = db.Column(db.Integer(), primary_key=True)
child_id = db.Column(db.Integer, db.ForeignKey('child.id'))
name = db.Column(db.String)

class Child(db.Model):
fields = ['id', 'name', 'toys']
id = db.Column(db.Integer(), primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))
name = db.Column(db.String)
toys = db.relationship('Toy')

class Parent(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String)
children = db.relationship('Child')

class ToySchema(ma.ModelSchema):
class Meta:
model = Toy

class ChildSchema(ma.ModelSchema):
class Meta:
model = Child

class ParentSchema(ma.ModelSchema):
class Meta:
model = Parent

db.create_all()
if __name__ == '__main__':
parent = Parent(
name='kay',
children=[
Child(
name='Taylor',
toys=[Toy(name='video game')],
),
Child(
name='Paige',
toys=[Toy(name='baby')],
),
],
)
db.session.add(parent)
db.session.commit()
print(ParentSchema().dump(parent))
This example is working for me, so you might focus on debugging your BaseModel implementation.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.

The docs for marshmallow-sqlalchemy show how to overload relationships with nested fields.

https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#overriding-generated-fields

class ChildSchema(ma.ModelSchema):
    toys = ma.Nested(ToySchema, many=True)
    class Meta:
        model = Child


class ParentSchema(ma.ModelSchema):
    children = ma.Nested(ChildSchema, many=True)
    class Meta:
        model = Parent


db.create_all()
if __name__ == '__main__':
    schema = ParentSchema()
    data = {'name': 'kay', 
      'id': 1,
     'children': [
                  {'name': 'Taylor', 'id': 1, 
                    'toys': [
                      {'name': 'video game','id': 1 }
                      ]
                   }, 
                  {'name': 'Paige',  'id': 2, 
                   'toys': [
                     {'name': 'baby', 'id': 1}
                  ]
             }], 
    }
    print(schema.load(data).data)
    # <Parent (transient 4583120144)>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

manoadamro picture manoadamro  Â·  3Comments

tadams42 picture tadams42  Â·  3Comments

jayennis22 picture jayennis22  Â·  4Comments

zohuchneg picture zohuchneg  Â·  3Comments

nickretallack picture nickretallack  Â·  4Comments