I've attempted the following:
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.event import listen
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
Base = declarative_base()
class Machine(Base):
__tablename__ = 'machines'
__table_args__ = {'sqlite_autoincrement': True}
machine_id = Column(Integer, primary_key=True)
widgets = relationship('Widget')
class Widget(Base):
__tablename__ = 'widgets'
__table_args__ = {'sqlite_autoincrement': True}
widget_id = Column(Integer, primary_key=True)
machine_id = Column(Integer, ForeignKey('machines.machine_id'),
nullable=False)
_gadgets = relationship('Gadget')
gadgets = association_proxy('_gadgets', 'json_repr',
creator=lambda kwargs: Gadget(**kwargs))
class Gadget(Base):
__tablename__ = 'gadgets'
__table_args__ = {'sqlite_autoincrement': True}
gadget_id = Column(Integer, primary_key=True)
widget_id = Column(Integer, ForeignKey('widgets.widget_id'),
nullable=False)
machine_id = Column(Integer, nullable=False)
a = Column(String)
b = Column(String)
c = Column(Integer)
@property
def json_repr(self):
return dict(a=self.a, b=self.b, c=self.c)
@staticmethod
def update_machine_ids(session, flush_context):
widgets = [w for w in session.new if isinstance(w, Widget)]
widgets.extend(w for w in session.dirty if isinstance(w, Widget))
print widgets
for widget in widgets:
session.query(Gadget).with_parent(widget).update(
{"machine_id": widget.machine_id})
if __name__ == '__main__':
engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.bind = engine
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
listen(Session, 'after_flush', Gadget.update_machine_ids)
session = Session()
m = Machine()
w = Widget()
session.add(m)
m.widgets.append(w)
w.gadgets.append(dict(a='1', b='2'))
session.commit()
I still get an integrity error because the after_flush happens after I've
already tried to insert the null gadgets. If I move the flush after the
widget is added to the session, but before the gadgets are, then the
query(Gadget).with_parent(widget) obviously won't find anything.
Maybe I should listen for Widget load events?
On Wed, Jul 3, 2013 at 5:07 PM, Michael Bayer <[email protected]>wrote:
>
> On Jul 3, 2013, at 5:06 PM, Michael Bayer <[email protected]>
> wrote:
>
> > Do the UPDATE through Session.execute() so it's within the same
> transaction.
>
> .. or even just
> query(Gadget).with_parent(some_widget).update({"machine_id":
> some_widget.machine_id}), then you can have those Gadget objects refreshed
> in memory using synchronize_session, if that's important.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.