Last active
March 2, 2018 21:44
-
-
Save npilon/c716a3bfcee20ce9f134467255da6f58 to your computer and use it in GitHub Desktop.
A minimal example demonstrating how SQLAlchemy 1.2 breaks pickling of ORM objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Demonstrate how SQLAlchemy 1.2 breaks pickling of ORM objects. | |
This somewhat-contrived example shows a query scenario where: | |
- We have an object (Garply) | |
- It is related to a table of Foos | |
- Foos uses single-table polymorphism to hold multiple types | |
- We query a Garply and eager-load some of its Foos | |
- We then pickle this Garply and its Foos for hand-off to some other process. | |
Since it already has its Foos loaded, we know it won't need further database | |
accesses. | |
Under SQLAlchemy 1.1.x, this works. Under SQLAlchemy 1.2.x, pickle fails. | |
""" | |
import datetime | |
import pickle | |
from sqlalchemy import ( | |
Column, | |
Integer, | |
DateTime, | |
Text, | |
ForeignKey, | |
create_engine, | |
) | |
from sqlalchemy.orm import ( | |
sessionmaker, | |
scoped_session, | |
with_polymorphic, | |
relationship, | |
subqueryload, | |
) | |
from sqlalchemy.ext.declarative import ( | |
declarative_base, | |
) | |
Base = declarative_base() | |
class Foo(Base): | |
__tablename__ = 'foo' | |
id = Column(Integer, primary_key=True) | |
identity = Column(Text) | |
created = Column(DateTime, default=datetime.datetime.now) | |
garply_id = Column(ForeignKey('garply.id')) | |
__mapper_args__ = { | |
'polymorphic_on': identity, | |
'polymorphic_identity': 'foo', | |
} | |
class Bar(Foo): | |
__mapper_args__ = { | |
'polymorphic_identity': 'bar', | |
} | |
class Baz(Foo): | |
__mapper_args__ = { | |
'polymorphic_identity': 'baz', | |
} | |
class Garply(Base): | |
__tablename__ = 'garply' | |
id = Column(Integer, primary_key=True) | |
foos = relationship(Foo) | |
BarBaz = with_polymorphic(Foo, [Bar, Baz]) | |
# SQLAlchemy session manager. Updated by lexdb.init_model(). | |
Session = scoped_session(sessionmaker()) | |
engine = create_engine('sqlite:///:memory:', echo=True) | |
Session.configure(bind=engine) | |
Base.metadata.create_all(engine) | |
garply_a = Garply() | |
Session.add(garply_a) | |
Session.flush() | |
Session.add(Bar(garply_id=garply_a.id)) | |
Session.add(Baz(garply_id=garply_a.id)) | |
Session.commit() | |
garply_again = Session.query(Garply).options( | |
subqueryload(Garply.foos.of_type(BarBaz)) | |
).first() | |
pickle.dumps(garply_again) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment