0

I am trying to understand how the the introspection of Marshmallow Schemas works. Here's a simple code example:

import os

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from pprint import pprint


db_file = "database.db"
if os.path.isfile(db_file):
    os.remove(db_file)

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_file}"
app.app_context().push()

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


class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    age = db.Column(db.Integer)


class MySchema(ma.Schema):
    class Meta:
        model = Person
        sqla_session = db.session
    

db.create_all()

alice = Person(name="Alice", age=25)
bob = Person(name="Bob", age=26)

db.session.add(alice)
db.session.add(bob)
db.session.commit()

persons = Person.query.all()
schema = MySchema(many=True)
result = schema.dump(persons)
pprint(result)

When I run this script the result I get is [{}, {}]. This tells me it does retrieve the Person objects from the database, but the Schema has no fields, so it just returns empty dicts. I expect this script to return [{"id": 0, "name": "Alice", "age": 25}, {"id": 1, "name": "Bob", "age": 26}], or something similar. Clearly the introspection of the database model has not happened. Why not? How should I modify this script to get the expected result?

For completeness, I am using Python 3.8.5 and the result of a pip freeze on my environment is this:

alembic==1.4.3
aniso8601==8.0.0
attrs==20.2.0
click==7.1.2
Flask==1.1.2
flask-marshmallow==0.14.0
Flask-Migrate==2.5.3
flask-restx==0.2.0
Flask-Script==2.0.6
Flask-SQLAlchemy==2.4.4
itsdangerous==1.1.0
Jinja2==2.11.2
jsonschema==3.2.0
Mako==1.1.3
MarkupSafe==1.1.1
marshmallow==3.8.0
marshmallow-sqlalchemy==0.23.1
psycopg2-binary==2.8.6
pyrsistent==0.17.3
python-dateutil==2.8.1
python-editor==1.0.4
pytz==2020.1
six==1.15.0
SQLAlchemy==1.3.20
Werkzeug==0.16.1

Note: I know I can get this to work by modifying my MySchema class like this:

class MySchema(ma.SQLAlchemySchema):
    class Meta:
        model = Person
        sqla_session = db.session
    
    id = ma.auto_field()
    name = ma.auto_field()
    age = ma.auto_field()

But this defies the purpose of having complete auto introspection. I want to avoid having to define the fields in two places.

D. de Vries
  • 417
  • 3
  • 12
  • 1
    Reading the notes about the [new schema classes](https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/240) - should you be using [SQLAlchemyAutoSchema](https://marshmallow-sqlalchemy.readthedocs.io/en/latest/api_reference.html#marshmallow_sqlalchemy.SQLAlchemyAutoSchema)? – pjcunningham Oct 16 '20 at 10:19

1 Answers1

0

Thanks to the comment by pjcunningham I managed to get this to work. Like he mentioned, all that had to be done was to replace ma.SQLAlchemySchema with ma.SQLAlchemyAutoSchema. After this change, the script returned the desired result.

D. de Vries
  • 417
  • 3
  • 12