[sqlalchemy] Event do not fire on m2m relation
Hi, I have some issue I try implement track logic I have 2 Models and connecting Table My first class class MODEL_1(object): # some values # relations: attr_1 = db.relationship('MODEL_2', secondary="test2test", lazy='dynamic', primaryjoin="MODEL_1.id == test2test.c.first_id", secondaryjoin='test2test.c.second_id == Site.entity_id') Second class class MODEL_2(object): # some values attr_2 = db.relationship('MODEL_1', secondary='test2test', lazy='dynamic') And relation table t_ = db.Table( 'test2test', db.Model.metadata, db.Column('first_id', db.Integer, db.ForeignKey('MODEL_1.entity_id'), nullable=False), db.Column('second_id', db.Integer, db.ForeignKey('MODEL_2.id'), nullable=False), db.UniqueConstraint('first_id', 'second_id', name='uq_test2test') ) I have some questions 1. can i do some table event what will fire, when will change some values in t_ table ? 2. if i set before_flush event and change some in MODEL_1, event fire, but session have no modified objects -- 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.
Re: [sqlalchemy] Event do not fire on m2m relation
Thx for your quick answer. About second question I have event, for example def track_instances_before_flush(session, context, instances): for obj in chain(session.new, session.dirty): if session.is_modified(obj): print "Before Flush" table_name = obj.__class__.__dict__['__tablename__'] print "Table_name ---", table_name print "Raw obj - ", obj state_before = {} state_after = {} mapper = inspect(obj) attrs = class_mapper(obj.__class__).column_attrs for attr in attrs: hist = mapper.attrs[attr.key].history if hist.has_changes(): state_before[attr.key] = get_history(obj, attr.key)[2][0] state_after[attr.key] = getattr(obj, attr.key) print "BEFORE -", state_before print "AFTER -", state_after and register it by listen(app.db.session, 'before_flush', track_instances_before_flush) and in output i see Before Flush Table_name --- MODEL_1 Raw obj - <'MODEL_1' id=2050> BEFORE - {} AFTER - {} In view I change only attr_1 for MODEL_1 On Monday, March 18, 2019 at 4:48:00 PM UTC+2, Mike Bayer wrote: > > On Mon, Mar 18, 2019 at 10:30 AM Денис Ралко > wrote: > > > > Hi, I have some issue > > > > I try implement track logic > > I have 2 Models and connecting Table > > > > My first class > > > > class MODEL_1(object): > > # some values > > > > # relations: > > attr_1 = db.relationship('MODEL_2', > >secondary="test2test", > >lazy='dynamic', > >primaryjoin="MODEL_1.id == > test2test.c.first_id", > >secondaryjoin='test2test.c.second_id == > Site.entity_id') > > > > Second class > > > > class MODEL_2(object): > > # some values > > attr_2 = db.relationship('MODEL_1', secondary='test2test', > lazy='dynamic') > > > > > > And relation table > > > > > > t_ = db.Table( > > 'test2test', > > db.Model.metadata, > > > > db.Column('first_id', db.Integer, > > db.ForeignKey('MODEL_1.entity_id'), > > nullable=False), > > db.Column('second_id', db.Integer, > > db.ForeignKey('MODEL_2.id'), > > nullable=False), > > db.UniqueConstraint('first_id', 'second_id', name='uq_test2test') > > ) > > > > > > I have some questions > > > > 1. can i do some table event what will fire, when will change some > values in t_ table ? > > via the relationship, sure, use @validates or AttributeEvents for > MODEL_1.attr1, MODEL_2.attr2 > > > https://docs.sqlalchemy.org/en/latest/orm/events.html?highlight=attributeevents#sqlalchemy.orm.events.AttributeEvents > > > > > > > 2. if i set before_flush event and change some in MODEL_1, event fire, > but session have no modified objects > > you would need to send along a complete example illustrating what you're > doing. > > > > > > > -- > > 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+...@googlegroups.com . > > To post to this group, send email to sqlal...@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.
Re: [sqlalchemy] Event do not fire on m2m relation
Sorry, my mistake Site.entity_id == MODEL_2.id And I solve my problem by change mapper.attrs -> mapper.column_attrs And now I want to ask you Can event directly set on Table colums? On Monday, March 18, 2019 at 10:28:54 PM UTC+2, Mike Bayer wrote: > > On Mon, Mar 18, 2019 at 11:07 AM Денис Ралко > wrote: > > > > Thx for your quick answer. > > About second question > > > > I have event, for example > > > > def track_instances_before_flush(session, context, instances): > > for obj in chain(session.new, session.dirty): > > if session.is_modified(obj): > > print "Before Flush" > > > > table_name = obj.__class__.__dict__['__tablename__'] > > > > print "Table_name ---", table_name > > > > > > print "Raw obj - ", obj > > > > state_before = {} > > state_after = {} > > mapper = inspect(obj) > > attrs = class_mapper(obj.__class__).column_attrs > > > > for attr in attrs: > > hist = mapper.attrs[attr.key].history > > if hist.has_changes(): > > state_before[attr.key] = get_history(obj, > attr.key)[2][0] > > state_after[attr.key] = getattr(obj, attr.key) > > > > print "BEFORE -", state_before > > print "AFTER -", state_after > > > > > > > > and register it by > > > > listen(app.db.session, 'before_flush', track_instances_before_flush) > > the code you've sent is still incomplete, for example i dont know what > "Site" is, but if you want to track relationships you need to look at > mapper.attrs or mapper.relationship_attrs.POC below with what I > could derive from your code fragments. > > from __future__ import print_function > > from itertools import chain > > from sqlalchemy import Column > from sqlalchemy import create_engine > from sqlalchemy import ForeignKey > from sqlalchemy import inspect > from sqlalchemy import Integer > from sqlalchemy import Table > from sqlalchemy import UniqueConstraint > from sqlalchemy.event import listen > from sqlalchemy.ext.declarative import declarative_base > from sqlalchemy.orm import class_mapper > from sqlalchemy.orm import relationship > from sqlalchemy.orm import Session > > Base = declarative_base() > > > class MODEL_1(Base): > __tablename__ = "MODEL_1" > > entity_id = Column(Integer, primary_key=True) > > # Don't know what "Site" is > # attr_1 = relationship( > #"MODEL_2", > #secondary="test2test", > #lazy="dynamic", > #primaryjoin="MODEL_1.id == test2test.c.first_id", > #secondaryjoin="test2test.c.second_id == Site.entity_id", > # ) > > > class MODEL_2(Base): > __tablename__ = "MODEL_2" > > id = Column(Integer, primary_key=True) > > attr_2 = relationship("MODEL_1", secondary="test2test", > lazy="dynamic") > > > t_ = Table( > "test2test", > Base.metadata, > Column( > "first_id", Integer, ForeignKey("MODEL_1.entity_id"), > nullable=False > ), > Column("second_id", Integer, ForeignKey("MODEL_2.id"), > nullable=False), > UniqueConstraint("first_id", "second_id", name="uq_test2test"), > ) > > def track_instances_before_flush(session, context, instances): > for obj in chain(session.new, session.dirty): > if session.is_modified(obj): > print("Before Flush") > > table_name = obj.__class__.__dict__["__tablename__"] > > print("Table_name ---", table_name) > > print("Raw obj - ", obj) > > state_before = {} > state_after = {} > mapper = inspect(obj) > attrs = class_mapper(obj.__class__).attrs > > for attr in attrs: > hist = mapper.attrs[attr.key].history > if hist.has_changes(): > state_before[attr.key] = hist[2] or hist[1] > state_after[attr.key] = hist[0] > > print("BEFORE -", state_before) > print("AFTER -", state_after) > > > e =