marshmallow-sqlalchemy
marshmallow-sqlalchemy provides integration between the SQLAlchemy ORM and the marshmallow (de)serialization library. It simplifies creating schemas for SQLAlchemy models, enabling automatic field generation and handling of relationships. The current version is 1.5.0, and it follows a release cadence generally aligned with its core dependencies, marshmallow and SQLAlchemy, with major updates addressing compatibility and new features.
Common errors
-
ModuleNotFoundError: No module named 'marshmallow_sqlalchemy'
cause The `marshmallow-sqlalchemy` package is not installed or not accessible in the current Python environment. This often occurs due to incorrect virtual environment activation or installation issues.fixEnsure your virtual environment is activated and install the package using `pip install marshmallow-sqlalchemy`. -
AttributeError: 'Model' object has no attribute '_sa_instance_state'
cause This error typically indicates that the SQLAlchemy model passed to `SQLAlchemyAutoSchema` or `SQLAlchemySchema` has not been properly mapped or registered with an SQLAlchemy session, or it's not a declarative base model instance.fixEnsure your SQLAlchemy model is correctly defined using SQLAlchemy's declarative base, and that you are passing a mapped model class (not an instance) to the schema's `Meta.model` attribute. -
TypeError: __init__() missing 1 required positional argument: 'session'
cause When using `marshmallow-sqlalchemy` schemas that need to interact with a database session (e.g., for resolving relationships or lazy loading), the schema instance requires an active SQLAlchemy session to be passed during initialization.fixPass an active SQLAlchemy session to your schema instance: `MySchema(session=db.session)` (assuming `db.session` is your SQLAlchemy session object). -
KeyError: 'Cannot resolve column 'some_column' on model 'SomeModel'.'
cause This error occurs when you try to declare a field in your `marshmallow-sqlalchemy` schema that does not correspond to an existing column or relationship on the associated SQLAlchemy model.fixVerify that 'some_column' exactly matches a column or relationship name defined in your `SomeModel` SQLAlchemy class. Check for typos or ensure the column is indeed part of the model.
Warnings
- breaking The `load_instance` argument to `SQLAlchemySchema` and `SQLAlchemyAutoSchema` constructors was removed in v1.0.0. Its functionality moved to the `load` method.
- breaking In v1.0.0, the `session` argument to `SQLAlchemySchema` and `SQLAlchemyAutoSchema` constructors no longer defaults to `None`. If `Meta.sqla_session` is not defined, you must pass the `session` explicitly when initializing the schema if you have relationship fields.
- gotcha Nesting SQLAlchemy models with relationships can lead to N+1 query problems if not handled carefully, and may require eager loading.
- gotcha Field overrides in `SQLAlchemyAutoSchema` must be placed directly in the schema class, not within the `Meta` class.
- gotcha When performing partial updates on an existing instance, not providing all required fields in the input data can lead to a `ValidationError` for missing data if `partial=True` is not used.
- gotcha When performing partial updates on an existing instance using `schema.load(data, instance=existing_object)`, a `ValidationError` for 'Missing data for required field' can occur if `partial=True` is not provided. By default, `load` expects all fields marked as `required=True` (or implicitly required by the model's non-nullable columns) to be present in `data`, even for updates.
Install
-
pip install marshmallow-sqlalchemy
Imports
- SQLAlchemyAutoSchema
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
- SQLAlchemySchema
from marshmallow_sqlalchemy import SQLAlchemySchema
Quickstart
import datetime
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.orm import sessionmaker, declarative_base
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from marshmallow import fields
# 1. Define SQLAlchemy Base and Model
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
email = Column(String(100), unique=True, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.now)
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}')>"
# 2. Set up database (in-memory SQLite for example)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# 3. Define Marshmallow Schema for the User model
class UserSchema(SQLAlchemyAutoSchema):
class Meta:
model = User
load_instance = True # Optional: Allows loading data into existing instances
sqla_session = session # Essential for relationship handling
# fields = ('id', 'name', 'email', 'created_at') # Explicit fields
# Example of overriding a field (optional)
created_at = fields.DateTime(format='%Y-%m-%d %H:%M:%S')
# 4. Usage Example
user_data = {
'name': 'Alice Smith',
'email': 'alice@example.com'
}
# Create a schema instance
user_schema = UserSchema()
# Deserialize (load) data to create a new User object
new_user = user_schema.load(user_data, session=session)
session.add(new_user)
session.commit()
print(f"Created user: {new_user}")
# Serialize (dump) an existing User object
serialized_user = user_schema.dump(new_user)
print(f"Serialized user: {serialized_user}")
# Update an existing user
update_data = {'name': 'Alicia Smith'}
alice = session.query(User).filter_by(email='alice@example.com').first()
updated_user = user_schema.load(update_data, instance=alice, session=session)
session.add(updated_user)
session.commit()
print(f"Updated user: {updated_user}")
session.close()