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 <mike...@zzzcomputing.com>wrote:

>
> On Jul 3, 2013, at 5:06 PM, Michael Bayer <mike...@zzzcomputing.com>
> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> 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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to