It's still a little bit long because you need the many to many relationships off chain to at least variable_region, but I can send that if the below doesn't clear things up for you:
I finally got it to work by updating the "business logic" script that (at least from my current analysis and testing) but in order to do so the chain.variable_regions and chain.constant_regions collections/relationships must be manually emptied (along with a couple other minor tweaks and some errors i spotted in the original example but that don't have an impact on the problem) The question/"issue" I have is that I was expecting those associations to be removed automatically if I delete the chain object. Is that incorrect? molecules = ( session.query(TestMolecule) .filter(TestMolecule.label.in_(["molecule1", "molecule2", "molecule3"])) .all() ) for molecule in molecules: session.delete(molecule) orphan_chains = ( session.query(TestChain).filter(~TestChain.molecules.any()).all() ) for orphan_chain in orphan_chains: orphan_chain.var_regions.clear() orphan_chain.const_regions.clear() session.delete(orphan_chain). On Wed, Apr 14, 2021 at 1:19 PM Mike Bayer <mike...@zzzcomputing.com> wrote: > > > On Wed, Apr 14, 2021, at 11:45 AM, Mark Aquino wrote: > > Thanks. I’ll take a stab at this approach. To back up a little bit my main > confusion is around why the association tables aren’t updating as expected. > As I understand it, without cascades configured, the default behavior > should be to remove associations from those tables. > > > that's correct, assuming the objects on either side are being deleted or > if the collection to which the association refers towards is being > emptied. > > > > > > If I configure cascades like on delete=cascade then the associated objects > themselves are set to also be deleted (as I would expect). In the no > cascades scenario, if I delete the test_chain then the orm should remove > its rows from test_chain_var_region and test_chain_const_region (this > occurs after the test_molecule is already deleted so any corresponding > test_molecule_chain rows are already removed) but the constraint error > occurs because it leaves them there. > > > Here is where we need to work with a more succinct example, as the example > given is too long and verbose so it's hard for me to isolate > where SQLAlchemy doing the wrong thing, as in the case earlier where it > seemed to me the scope of the related delete statement needed to be > expanded, but that wasn't what you were tring to do. > > Below is a structure that paraphrases what I think is part of your model, > more or less, which at the moment is able to delete the "Chain" object. If > you can modify the below script to illustrate more specifically the > structural pattern that's present and the originating, single delete() > statement you expect to succeed, then I can give you a better answer what's > going on. > > from sqlalchemy import Column > from sqlalchemy import create_engine > from sqlalchemy import ForeignKey > from sqlalchemy import Integer > from sqlalchemy import Table > from sqlalchemy.ext.declarative import declarative_base > from sqlalchemy.orm import relationship > from sqlalchemy.orm import Session > > Base = declarative_base() > > > class Molecule(Base): > __tablename__ = "molecule" > > id = Column(Integer, primary_key=True) > > chain = relationship("Chain", back_populates="molecules") > chain_id = Column(ForeignKey("chain.id", ondelete="CASCADE")) > > > chain_to_related = Table( > "chain_to_related", > Base.metadata, > Column("chain_id", ForeignKey("chain.id"), primary_key=True), > Column("related_id", ForeignKey("related_to_chain.id"), > primary_key=True), > ) > > > class Chain(Base): > __tablename__ = "chain" > id = Column(Integer, primary_key=True) > related = relationship("RelatedToChain", secondary=chain_to_related) > > molecules = relationship("Molecule", back_populates="chain") > > > class RelatedToChain(Base): > __tablename__ = "related_to_chain" > id = Column(Integer, primary_key=True) > > > e = create_engine("postgresql://scott:tiger@localhost/test", echo=True) > Base.metadata.drop_all(e) > Base.metadata.create_all(e) > > s = Session(e) > > c1 = Chain() > m1 = Molecule(chain=c1) > r1 = RelatedToChain() > c1.related.append(r1) > > s.add_all([c1, m1, r1]) > s.commit() > > > s.delete(c1) > s.commit() > > > > > > > > > > > > > It works as expected with deleting the molecule, and test_molecule_chain > rows are removed but not test_chains hence why I need to perform the > additional logic to remove the stranded chains that are left behind but not > linked to any test_molecules anymore. Am I doing something differently in > my test_molecule configuration that I’m just not seeing? > > Mark Aquino > ------------------------------ > > *From:* sqlalchemy@googlegroups.com <sqlalchemy@googlegroups.com> on > behalf of Mike Bayer <mike...@zzzcomputing.com> > *Sent:* Wednesday, April 14, 2021 11:21:28 AM > *To:* noreply-spamdigest via sqlalchemy <sqlalchemy@googlegroups.com> > *Subject:* Re: [sqlalchemy] Issue with "complex" many 2 many delete, FK > violation > > > hey there- > > The general strategy, if you want to write business logic that checks > things, takes other actions, etc. when changes occur in the session, is to > use the before_flush event handler: > https://docs.sqlalchemy.org/en/14/orm/events.html?highlight=before_flush#sqlalchemy.orm.SessionEvents.before_flush > > in this event, you can review the linkages on the objects in question and > emit additional statements if desired. Note this is because you said you > didn't want to use CASCADE rules on your foreign keys; that would allow > your script to pass without change. > > The general form of using before_flush(), where I've paraphrased a few of > your business rules below in the form of pseduocode, looks like: > > from sqlalchemy import event > > > @event.listens_for(SomeSessionOrFactory, 'before_flush') > def receive_before_flush(session, flush_context, instances): > for obj in session.deleted: > if isinstance(obj, TestMolecule): > check_obj_not_linked_to_other_test_molecules(obj) > elif isinstance(obj, TestChain): > if should_delete_related_test_mol_sequence(obj): > session.delete(obj.related_test_mol_sequence) > > # ... etc > > > Obviously you'd need to work out the specifics of your model here, but > within before_flush() you can respond to all objects that have pending > changes and/or deletions, and add additional custom rules and actions where > you are free to further modify the state of the Session, which will take > effect within this same flush operation. > > > > > > > On Tue, Apr 13, 2021, at 5:29 PM, Mark Aquino wrote: > > Hi Mike, > > Sorry about the indentations. > > I'm not sure I understand the changes you made to the script after delete > as it removes all test_chains, test_var_regions, and test_const regions > that are still referenced by the other test_molecules. The only way I've > been able to get the delete to work properly is to manually delete > test_var_regions and test_const_regions first and then delete the > test_molecules, but the ideal outcome I'm trying to achieve is that when a > test_molecule is deleted: > > 1. that the system checks if the chains connected to it are removed > if they are not linked to other test_molecules. > 2. if a test_chain is going to be deleted then > 1. the test_mol_sequence associated with it is deleted if it is no > longer associated with any other test_chains > 2. any test_var_regions and test_const_regions are deleted if they > are not associated with any other test_chains > 3. and finally if a test_mol_sequence is deleted that any > test_mol_sequence_features are deleted if they are not associated with any > other test_mol_sequences. > > > To make things a little easier to explain, if we just are dealing with > molecule1 and molecule4 there are only 3 unique test_chains: heavy_chain_1, > light_chain_1, and heavy_chain_2 > if I deleted molecule1, I would want to retain heavy_chain_2 and > light_chain_1 and delete heavy_chain_1 as it was no longer associated with > any test_molecule. Ideally, then I would remove any test_const_regions and > test_var_regions that are no longer associated with any test_chains. > Because heavy_chain_1 shares the same test_var_region as heavy_chain_2, > that test_var_region would remain in the system but the test_const_region > unique to heavy_chain_1 would be deleted along with the test_mol_sequence > and test_mol_sequence_features associated with it. > > molecule1.chains.add(heavy_chain_1) > molecule1.chains.add(light_chain_1) > #molecule2.chains.add(heavy_chain_2) > #molecule2.chains.add(light_chain_2) > #molecule3.chains.add(heavy_chain_1) > #molecule3.chains.add(light_chain_2) > molecule4.chains.add(heavy_chain_2) > molecule4.chains.add(light_chain_1) > > > light_chain_1_sequence = TestMolSequence(content="taglconst1VAR1") > heavy_chain_1_sequence = TestMolSequence(content="tagheavyconstant1VAR2") > heavy_chain_2_sequence = TestMolSequence(content="tagheavyconstant2VAR2") > light_chain_2_sequence = TestMolSequence(content="taglconst1VAR3") > > > Does that make sense? > > > > On Tue, Apr 13, 2021 at 4:50 PM Mike Bayer <mike...@zzzcomputing.com> > wrote: > > > Hi there - > > I would ask that you try to make sure your formatting is maintained when > posting examples especially such long ones as I had to re-indent it in > order to run this. > > The delete at the end is failing because of incomplete cascade rules. > The DELETE against "test_mol_sequence" seeks to CASCADE as configured to > the other three tables,, which then fail because there are non-cascading > FKs in the association tables. We can see this via the message: > > update or delete on table "test_var_region" violates foreign key > constraint "test_chain_var_region_var_region_id_fkey" on table > "test_chain_var_region" > DETAIL: Key (id)=(1) is still referenced from table > "test_chain_var_region". > > [SQL: DELETE FROM test_mol_sequence WHERE test_mol_sequence.id = %(id)s] > > > it's DELETEing from test_mol_sequence but the error is against a totally > different table. That's postgresql's cascade. > > if you want these CASCADEs to remain in place then you'd need to ensure > that those linked rows can be deleted without any rows being present in the > association tables. > > I can modify your test at the end to fully DELETE these rows without > qualifying for those that have empty collections only and the script then > passes, because now it's deleting those rows that would otherwise be > dependent on by "test_var_region" and therefore "test_mol_sequence", so > there's nothing unexpected going on. Easiest solution here would be to > add CASCADE rules to the association tables also. If you want that to be > prevented as you mention, and instead expect the script to explicitly > delete those depending rows, then your script is already achieving that. > the "business logic" so to speak in this case would be as below: > > orphan_chains = ( > session.query(TestChain). > # filter(~TestChain.molecules.any()). > all() > ) > for chain in orphan_chains: > session.delete(chain) > > orphan_vrs = ( > session.query(TestVarRegion) > # .filter(~TestVarRegion.chains.any()) > .all() > ) > for orphan_vr in orphan_vrs: > session.delete(orphan_vr) > orphan_crs = ( > session.query(TestConstRegion) > # .filter(~TestConstRegion.chains.any()) > .all() > ) > for orphan_cr in orphan_crs: > session.delete(orphan_cr) > orphan_sequences = ( > session.query(TestMolSequence) > # .filter(~TestMolSequence.chains.any()) > .all() > ) > > > > > > > > > > On Tue, Apr 13, 2021, at 10:03 AM, maqui...@gmail.com wrote: > > I need to delete the association table rows for many to many relationships > when I delete one, but the default behavior (to remove those rows) does not > seem to work in my case. > > I have multiple levels of many to many relationships, as you can see in > the example I'll provide below and when I delete a "parent" afterwards I > try to clean up any children left behind that have no other parents. > However, these children are in many to many relationships with other > children and that's when the ORM fails to attempt to remove those children > from their related association tables (at least, in a way that I expect). > > The issue is error is: > def do_executemany(self, cursor, statement, parameters, context=None): > if self.executemany_mode is EXECUTEMANY_DEFAULT: > > cursor.executemany(statement, parameters) > E sqlalchemy.exc.IntegrityError: > (psycopg2.errors.ForeignKeyViolation) update or delete on table > "test_var_region" violates foreign key constraint > "test_chain_var_region_var_region_id_fkey" on table "test_chain_var_region" > E DETAIL: Key (id)=(1) is still referenced from table > "test_chain_var_region". > E > E [SQL: DELETE FROM test_mol_sequence WHERE test_mol_sequence.id > = %(id)s] > E [parameters: ({'id': 5}, {'id': 6}, {'id': 7}, {'id': 8}, > {'id': 9}, {'id': 10})] > E (Background on this error at: http://sqlalche.me/e/gkpj) > > The desired effect, of course, is that the rows in test_chain_var_region > that reference the deleted chains removed. I've tried several strategies > to do this but with no change in this behavior. > > Cascades could be an issue, and I would rather handle removal of any > "orphan" rows in the model tables via business logic than have the database > cascade deletes and potentially remove rows that are associated with other > objects. > > import pytest > from sqlalchemy import ( > Table, > Column, > Integer, > String, > ForeignKey, > create_engine, > ) > from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta > from sqlalchemy.orm import relationship, Session > from sqlalchemy.util import OrderedSet > > > Base: DeclarativeMeta = declarative_base() > engine = create_engine( > "postgresql://postgres:postgres@localhost:5432/espresso", echo=True > ) > test_chain_const_region = Table( > "test_chain_const_region", > Base.metadata, > Column("chain_id", Integer, ForeignKey("test_chain.id")), > Column("const_region_id", Integer, ForeignKey("test_const_region.id")), > ) > test_chain_var_region = Table( > "test_chain_var_region", > Base.metadata, > Column("chain_id", Integer, ForeignKey("test_chain.id")), > Column("var_region_id", Integer, ForeignKey("test_var_region.id")), > ) > test_molecule_chain = Table( > "test_molecule_chain", > Base.metadata, > Column("molecule_id", Integer, ForeignKey("test_molecule.id")), > Column("chain_id", Integer, ForeignKey("test_chain.id")), > ) > > test_mol_sequence_feat_mol_sequence = Table( > "test_mol_sequence_feat_mol_sequence", > Base.metadata, > Column("mol_sequence_feat_id", Integer, ForeignKey(" > test_mol_sequence_feat.id")), > Column("mol_sequence_id", Integer, ForeignKey("test_mol_sequence.id")), > ) > > > class TestMolecule(Base): > __tablename__ = "test_molecule" > id = Column(Integer, primary_key=True) > label = Column(String) > chains = relationship( > "TestChain", > secondary=test_molecule_chain, > collection_class=OrderedSet, > back_populates="molecules", > ) > > > class TestMolSequence(Base): > __tablename__ = "test_mol_sequence" > > id = Column(Integer, primary_key=True) > content = Column(String, nullable=False, unique=True) > parent_features = relationship( > "TestMolSequenceFeat", > secondary=test_mol_sequence_feat_mol_sequence, > collection_class=OrderedSet, > back_populates="feature_sequences", > single_parent=True, > ) > chains = relationship( > "TestChain", back_populates="mol_sequence", collection_class=OrderedSet > ) > > > class TestMolSequenceFeat(Base): > __tablename__ = "test_mol_sequence_feat" > > id = Column(Integer, primary_key=True) > molecule_sequence_id = Column( > Integer, ForeignKey("test_mol_sequence.id", ondelete="CASCADE"), > ) > molecule_sequence = relationship("TestMolSequence",) > start = Column(Integer) > stop = Column(Integer) > feature_sequences = relationship( > "TestMolSequence", > secondary=test_mol_sequence_feat_mol_sequence, > collection_class=OrderedSet, > back_populates="parent_features", > # single_parent=True, > ) > > > class TestChain(Base): > __tablename__ = "test_chain" > > id = Column(Integer, primary_key=True) > label = Column(String) > chain_type = Column(String) > mol_sequence_id = Column(Integer, ForeignKey("test_mol_sequence.id")) > mol_sequence = relationship("TestMolSequence", back_populates="chains") > molecules = relationship( > "TestMolecule", > secondary=test_molecule_chain, > collection_class=OrderedSet, > back_populates="chains", > ) > var_regions = relationship( > "TestVarRegion", > secondary=test_chain_var_region, > collection_class=OrderedSet, > back_populates="chains", > ) > const_regions = relationship( > "TestConstRegion", > secondary=test_chain_const_region, > collection_class=OrderedSet, > back_populates="chains", > ) > > > class TestVarRegion(Base): > __tablename__ = "test_var_region" > > id = Column(Integer, primary_key=True) > molecule_sequence_id = Column( > Integer, ForeignKey("test_mol_sequence.id", ondelete="CASCADE"), > ) > description = Column(String) > additional_information = Column(String) > label = Column("label", String, nullable=True, unique=False) > molecule_sequence = relationship("TestMolSequence") > chains = relationship( > "TestChain", > secondary=test_chain_var_region, > collection_class=OrderedSet, > back_populates="var_regions", > passive_deletes=True, > ) > > > class TestConstRegion(Base): > __tablename__ = "test_const_region" > > id = Column(Integer, primary_key=True) > molecule_sequence_id = Column( > Integer, ForeignKey("test_mol_sequence.id", ondelete="CASCADE"), > ) > description = Column(String) > additional_information = Column(String) > label = Column("label", String, nullable=True, unique=False) > molecule_sequence = relationship("TestMolSequence") > chains = relationship( > "TestChain", > secondary=test_chain_const_region, > collection_class=OrderedSet, > back_populates="const_regions", > passive_deletes=True, > ) > > > class TestManyToMany: > @pytest.fixture > def engine(self): > return create_engine( > "postgresql://postgres:postgres@localhost:5432/espresso", echo=True > ) > > @pytest.fixture > def session(self): > > *"""Returns an sqlalchemy session, and after the test tears down > everything properly.""" *connection = engine.connect() > # begin the nested transaction > transaction = connection.begin() > # use the connection with the already started transaction > session = Session(bind=connection) > > yield session > > session.close() > # roll back the broader transaction > transaction.commit() > # put back the connection to the connection pool > connection.close() > > @pytest.mark.create_m2m_models > def test_create_m2m_models(self, engine): > > Base.metadata.drop_all(bind=engine) > Base.metadata.create_all(bind=engine) > > @pytest.mark.seed_m2m_data > def test_m2m_seeding_data(self, engine, session): > > molecule1 = TestMolecule(label="molecule1") > molecule2 = TestMolecule(label="molecule2") > molecule3 = TestMolecule(label="molecule3") > molecule4 = TestMolecule(label="molecule4") > light_chain_1_sequence = TestMolSequence(content="taglconst1VAR1") > heavy_chain_1_sequence = TestMolSequence(content="tagheavyconstant1VAR2") > heavy_chain_2_sequence = TestMolSequence(content="tagheavyconstant2VAR2") > light_chain_2_sequence = TestMolSequence(content="taglconst1VAR3") > heavy_chain_1 = TestChain( > chain_type="heavy", mol_sequence=light_chain_1_sequence > ) > light_chain_1 = TestChain( > chain_type="light", mol_sequence=heavy_chain_1_sequence > ) > light_chain_2 = TestChain( > chain_type="light", mol_sequence=light_chain_2_sequence > ) > heavy_chain_2 = TestChain( > chain_type="heavy", mol_sequence=heavy_chain_2_sequence > ) > > molecule1.chains.add(heavy_chain_1) > molecule1.chains.add(light_chain_1) > molecule2.chains.add(heavy_chain_2) > molecule2.chains.add(light_chain_2) > molecule3.chains.add(heavy_chain_1) > molecule3.chains.add(light_chain_2) > molecule4.chains.add(heavy_chain_2) > molecule4.chains.add(light_chain_1) > > tag_sequence = TestMolSequence(content="tag") > light_constant_region_seq = TestMolSequence(content="lconst1") > heavy_constant_region_1_seq = TestMolSequence(content="heavyconstant1") > heavy_constant_region_2_seq = TestMolSequence(content="heavyconstant2") > vr1_seq = TestMolSequence(content="VAR1") > vr2_seq = TestMolSequence(content="VAR2") > vr3_seq = TestMolSequence(content="VAR3") > # lc2_const_region_seq = TestMolSequence(content="lconst") > lc1_tag_feature = TestMolSequenceFeat( > start=0, stop=3, molecule_sequence=light_chain_1_sequence > ) > lc1_const_region_feature = TestMolSequenceFeat( > start=3, stop=10, molecule_sequence=light_chain_1_sequence > ) > lc1_var_region_feature = TestMolSequenceFeat( > start=10, stop=14, molecule_sequence=light_chain_1_sequence > ) > hc1_tag_feature = TestMolSequenceFeat( > start=0, stop=3, molecule_sequence=heavy_chain_1_sequence > ) > hc1_const_region_feature = TestMolSequenceFeat( > start=3, stop=17, molecule_sequence=heavy_chain_1_sequence > ) > hc1_var_region_feature = TestMolSequenceFeat( > start=17, stop=21, molecule_sequence=heavy_chain_1_sequence > ) > > hc2_tag_feature = TestMolSequenceFeat( > start=0, stop=3, molecule_sequence=heavy_chain_2_sequence > ) > hc2_const_region_feature = TestMolSequenceFeat( > start=3, stop=17, molecule_sequence=heavy_chain_2_sequence > ) > hc2_var_region_feature = TestMolSequenceFeat( > start=17, stop=21, molecule_sequence=heavy_chain_2_sequence > ) > > lc2_tag_feature = TestMolSequenceFeat( > start=0, stop=3, molecule_sequence=light_chain_2_sequence > ) > lc2_const_region_feature = TestMolSequenceFeat( > start=3, stop=10, molecule_sequence=light_chain_2_sequence > ) > lc2_var_region_feature = TestMolSequenceFeat( > start=10, stop=14, molecule_sequence=light_chain_2_sequence > ) > var_region1 = TestVarRegion(molecule_sequence=vr1_seq) > var_region2 = TestVarRegion(molecule_sequence=vr2_seq) > var_region3 = TestVarRegion(molecule_sequence=vr3_seq) > const_region1 = > TestConstRegion(molecule_sequence=light_constant_region_seq) > const_region2 = > TestConstRegion(molecule_sequence=heavy_constant_region_1_seq) > const_region3 = > TestConstRegion(molecule_sequence=heavy_constant_region_2_seq) > > light_chain_1.var_regions.add(var_region1) > heavy_chain_1.var_regions.add(var_region2) > heavy_chain_2.var_regions.add(var_region2) > light_chain_2.var_regions.add(var_region3) > > light_chain_1.const_regions.add(const_region1) > light_chain_2.const_regions.add(const_region1) > heavy_chain_1.const_regions.add(const_region2) > heavy_chain_2.const_regions.add(const_region3) > > lc1_tag_feature.feature_sequences.add(tag_sequence) > lc1_var_region_feature.feature_sequences.add(vr1_seq) > lc1_const_region_feature.feature_sequences.add(light_constant_region_seq) > > hc1_tag_feature.feature_sequences.add(tag_sequence) > hc1_var_region_feature.feature_sequences.add(vr2_seq) > hc1_const_region_feature.feature_sequences.add(heavy_constant_region_1_seq) > > lc2_tag_feature.feature_sequences.add(tag_sequence) > lc2_var_region_feature.feature_sequences.add(vr3_seq) > lc2_const_region_feature.feature_sequences.add(light_constant_region_seq) > > hc2_tag_feature.feature_sequences.add(tag_sequence) > hc2_var_region_feature.feature_sequences.add(vr2_seq) > hc2_const_region_feature.feature_sequences.add(heavy_constant_region_2_seq) > > session.add_all( > [ > heavy_chain_1, > light_chain_1, > light_chain_2, > heavy_chain_2, > molecule1, > molecule2, > molecule3, > molecule4, > # tag_sequence, > # lc1_tag_feature, > # lc1_const_region_feature, > # hc1_tag_feature, > # hc1_var_region_feature, > # lc1_tag_feature, > # lc2_const_region_feature, > ] > ) > session.commit() > > @pytest.mark.delete_test_m2m_models > def test_create_m2m(self, session): > molecule = session.query(TestMolecule).filter_by(label="molecule1").one() > session.delete(molecule) > session.query(TestChain).filter(~TestChain.molecules.any()).delete( > synchronize_session="fetch" > ) > session.expire_all() > orphan_chains = ( > session.query(TestChain).filter(~TestChain.molecules.any()).all() > ) > for chain in orphan_chains: > session.delete(chain) > orphan_vrs = ( > session.query(TestVarRegion).filter(~TestVarRegion.chains.any()).all() > ) > for orphan_vr in orphan_vrs: > session.delete(orphan_vr) > orphan_crs = ( > session.query(TestConstRegion) > .filter(~TestConstRegion.chains.any()) > .all() > ) > for orphan_cr in orphan_crs: > session.delete(orphan_cr) > orphan_sequences = ( > session.query(TestMolSequence).filter(~TestMolSequence.chains.any()).all() > ) > orphan_sequence: TestMolSequence > for orphan_sequence in orphan_sequences: > session.delete(orphan_sequence) > session.commit() > > > -- > 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 view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/7963c7d7-9053-436e-ae5b-f92519ddeb0en%40googlegroups.com > <https://groups.google.com/d/msgid/sqlalchemy/7963c7d7-9053-436e-ae5b-f92519ddeb0en%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > > -- > 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 view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/56bfe88d-8b81-4541-9192-86d42ebcc27f%40www.fastmail.com > <https://groups.google.com/d/msgid/sqlalchemy/56bfe88d-8b81-4541-9192-86d42ebcc27f%40www.fastmail.com?utm_medium=email&utm_source=footer> > . > > > -- > 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 view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/CAL6EnB4LLyBJiqLFaG9xO2wZAE08yeipo_Ap7M2h-Csk0JTamg%40mail.gmail.com > <https://groups.google.com/d/msgid/sqlalchemy/CAL6EnB4LLyBJiqLFaG9xO2wZAE08yeipo_Ap7M2h-Csk0JTamg%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > > > > -- > 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 a topic in the > Google Groups "sqlalchemy" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/sqlalchemy/-6vjYYTMPb4/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/13572dd1-155e-47e0-9e9c-976e0ec1c56b%40www.fastmail.com > <https://groups.google.com/d/msgid/sqlalchemy/13572dd1-155e-47e0-9e9c-976e0ec1c56b%40www.fastmail.com?utm_medium=email&utm_source=footer> > . > > > -- > 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 view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/BL0PR16MB2515A95197043547A667732CF04E9%40BL0PR16MB2515.namprd16.prod.outlook.com > <https://groups.google.com/d/msgid/sqlalchemy/BL0PR16MB2515A95197043547A667732CF04E9%40BL0PR16MB2515.namprd16.prod.outlook.com?utm_medium=email&utm_source=footer> > . > > > -- > 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 a topic in the > Google Groups "sqlalchemy" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/sqlalchemy/-6vjYYTMPb4/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/b2ae5c82-c1a0-4b9e-931f-b515e3e55bce%40www.fastmail.com > <https://groups.google.com/d/msgid/sqlalchemy/b2ae5c82-c1a0-4b9e-931f-b515e3e55bce%40www.fastmail.com?utm_medium=email&utm_source=footer> > . > -- 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 view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/CAL6EnB7D%3DC9ynmGHujWXWiYgN3cOVBYVRWs7x4dDpuOZwibnfw%40mail.gmail.com.