Skip to content

Instantly share code, notes, and snippets.

@jneves
Created September 26, 2018 15:35
Show Gist options
  • Save jneves/649c89a99b369f7d4be2751ea2d28f0a to your computer and use it in GitHub Desktop.
Save jneves/649c89a99b369f7d4be2751ea2d28f0a to your computer and use it in GitHub Desktop.
SQLAlchemy issue with joinedload and correlate_except on a column_property
from sqlalchemy import create_engine, select, and_, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Boolean, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, column_property, relationship, joinedload, deferred, undefer, load_only
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
password = Column(String)
group_id = Column(Integer, ForeignKey('groups.id'))
group = relationship('Group')
def __repr__(self):
return "<User(id=%d, name='%s', fullname='%s', password='%s')>" % (
self.id, self.name, self.fullname, self.password)
class Worker(User):
__tablename__ = 'workers'
id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), primary_key=True)
nino = Column(String)
employed = Column(Boolean)
group = relationship('WorkersGroup', backref='workers')
class Group(Base):
__tablename__ = 'groups'
id = Column(Integer, primary_key=True)
name = Column(String)
def __repr__(self):
return "<Group(id=%d, name='%s')>" % (self.id, self.name)
class WorkersGroup(Group):
__tablename__ = 'workers_groups'
id = Column(Integer, ForeignKey('groups.id', ondelete='CASCADE'), primary_key=True)
def __repr__(self):
return "<WorkersGroup(id=%d, name='%s', count='%r')>" % (
self.id, self.name, self.employee_count)
WorkersGroup.employee_count = column_property(
select([func.count(Worker.id)]).where(
and_(
Worker.id == User.id,
Worker.group_id == WorkersGroup.id,
Worker.nino.isnot(None)
)
).correlate_except(Worker, User)
)
Base.metadata.create_all(engine)
workers = WorkersGroup(name='workers')
session.add(workers)
contractors = WorkersGroup(name='contractors')
session.add(contractors)
session.flush()
ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
session.add(ed_user)
ed1_user = Worker(name='ed1', fullname='Ed1 Jones', group_id=workers.id, nino='ABC123')
session.add(ed1_user)
ed2_user = Worker(name='ed2', fullname='Ed2 Jones', group_id=workers.id)
session.add(ed2_user)
ed3_user = Worker(name='ed3', fullname='Ed3 Jones', group_id=contractors.id, nino='CBA321')
session.add(ed3_user)
ed4_user = Worker(name='ed4', fullname='Ed4 Jones', group_id=contractors.id, nino='CBA321')
session.add(ed4_user)
ed5_user = Worker(name='ed5', fullname='Ed5 Jones', group_id=contractors.id, nino='CBA321')
session.add(ed5_user)
session.flush()
# Depending on which of the following blocks happen first, the result is either 1 or 3
# Block 1
w = session.query(Worker).filter(Worker.id == 4).one()
print(w)
print(w.group.employee_count)
# Block 2
w = session.query(Worker).options(joinedload(Worker.group)).filter(Worker.id == 4).one()
print(w)
print(w.group.employee_count)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment