On Wed, Feb 7, 2018 at 7:16 AM, tonthon <tontho...@gmail.com> wrote: > Hi, > > I'd like to setup bidirectionnal data synchornization between the lastname > attribute of two related models > > class User(Base): > __tablename__ = 'users' > id = Column(Integer, primary_key=True) > lastname = Column(String(50)) > userdatas = relationship('UserDatas', > primaryjoin='User.id==UserDatas.user_id', back_populates='user', > uselist=False) > > class UserDatas(Base): > __tablename__ = 'userdatas' > id = Column(Integer, primary_key=True) > lastname = Column(String(50)) > user_id = Column(ForeignKey('users.id')) > user = relationship('User', primaryjoin='User.id==UserDatas.user_id') > > > I thought I could do something like this : > > def sync_lastname_user_to_userdatas(target, value, oldvalue, initiator): > target.userdatas.lastname = value > > listen(User.lastname, 'set', sync_lastname_user_to_userdatas) > > def sync_lastname_userdatas_to_user(target, value, oldvalue, initiator): > target.user.lastname = value > > listen(UserDatas.lastname, 'set', sync_lastname_userdatas_to_user) > > > The obvious problem here is the infinite loop that is generated > > So : > Is there a way to set an attribute without firing the 'set' event ? > > I tend to think there is a better way to do that, does anybody have an > advice to share ?
below is an example of the most correct way to do this, to support this use case I will add the "initiator" argument to the set_attribute() function within SQLAlchemy but this will work in all 1.1, 1.2 versions for now: from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import event from sqlalchemy import inspect def set_attribute(instance, key, value, initiator=None): """Set the value of an attribute, firing history events. This function is copied from the attributes module but adds the "initiator" argument. """ state = inspect(instance) dict_ = state.dict state.manager[key].impl.set(state, dict_, value, initiator) Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) lastname = Column(String(50)) userdatas = relationship( 'UserDatas', primaryjoin='User.id==UserDatas.user_id', back_populates='user', uselist=False) class UserDatas(Base): __tablename__ = 'userdatas' id = Column(Integer, primary_key=True) lastname = Column(String(50)) user_id = Column(ForeignKey('users.id')) user = relationship('User', primaryjoin='User.id==UserDatas.user_id') @event.listens_for(User.lastname, "set") def sync_lastname_user_to_userdatas(target, value, oldvalue, initiator): parentclass = initiator.parent_token.parent.class_ if parentclass is User: set_attribute(target.userdatas, "lastname", value, initiator) @event.listens_for(UserDatas.lastname, 'set') def sync_lastname_userdatas_to_user(target, value, oldvalue, initiator): parentclass = initiator.parent_token.parent.class_ if parentclass is UserDatas: set_attribute(target.user, "lastname", value, initiator) u1 = User(userdatas=UserDatas()) u1.lastname = 'foo' assert u1.userdatas.lastname == u1.lastname == 'foo' u1.userdatas.lastname = 'bar' assert u1.userdatas.lastname == u1.lastname == 'bar' > > Thanks in advance > > Regards, > Gaston Tjebbes > > https://www.majerti.fr > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > 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 https://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- 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 https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.