On Wed, Feb 3, 2021, at 6:23 PM, Christian Henning wrote: > Hi Mike, > > thanks for your advice! I'll make the changes. > > But let me ask you one thing. My classmethod create() is but more complex > than I have posted. It's meant to catch IntegrityError so that unique > constraints are enforced. Image a User table has a "unique" constraint on the > name. When I try to create a user with the same name the create() would catch > the exception and return the original user. I believe this only possible when > all objects are committed to the database. > > class ModelBase: > > @classmethod > def create(cls, session, **kwargs): > obj = cls(**kwargs) > try: > obj.save(session) > except IntegrityError: > # print('HOLA - Integrity Error') > > session.rollback() > obj = cls.find(session, **kwargs) > > return obj > > def save(self, session): > session.add(self) > session.commit() > > How would you solve the problem? Is there anything in the documentation?
yes, use a SAVEPOINT for that, so you can roll back to the savepoint and still have the transaction continue: https://docs.sqlalchemy.org/en/13/faq/sessions.html#but-why-does-flush-insist-on-issuing-a-rollback so you can place in your method: session.begin_nested(): session.add(obj) try: session.flush() except IntegrityError: session.rollback() else: session.commit() > > Thanks, > Christian > > > > > > On Wednesday, February 3, 2021 at 5:12:30 PM UTC-5 Mike Bayer wrote: >> __ >> the session.commit() method expires all attributes by default: >> >> https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing >> >> your code is organized in an unusual way such that transactions are being >> committed inside of attribute assignment operations: >> >> jack.addresses.append(Address.create(session)) >> >> We can expand this out as follows: >> >> addr = jack.addresses >> address = Address() >> session.add(address) >> session.commit() # <--- expires all attributes on "jack", "address", >> invalidates "addr" >> attr.append(address) # <--- this is invalid, transaction was already >> commited >> >> I would strongly advise keeping session scope manage external to the set of >> operations you are performing. See >> https://docs.sqlalchemy.org/en/13/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it >> for guidelines. >> >> >> On Wed, Feb 3, 2021, at 2:27 PM, Christian Henning wrote: >>> I don't understand why SQLAlchemy gives me the following warning: >>> >>> SAWarning: This collection has been invalidated. >>> util.warn("This collection has been invalidated.") >>> >>> Here is a minimal code example: >>> >>> ----------------- >>> ----------------- >>> >>> import sqlalchemy >>> print(sqlalchemy.__version__) >>> >>> from sqlalchemy import create_engine >>> from sqlalchemy import Column, Integer, ForeignKey >>> >>> from sqlalchemy.exc import IntegrityError >>> from sqlalchemy.ext.declarative import declarative_base >>> >>> from sqlalchemy.orm import relationship >>> from sqlalchemy.orm import sessionmaker >>> >>> Base = declarative_base() >>> >>> class ModelBase: >>> >>> @classmethod >>> def create(cls, session, **kwargs): >>> obj = cls(**kwargs) >>> session.add(obj) >>> session.commit() >>> >>> return obj >>> >>> >>> class User(ModelBase, Base): >>> __tablename__ = 'users' >>> >>> id = Column(Integer, primary_key=True) >>> >>> addresses = relationship("Address", order_by="Address.id", >>> back_populates="user") >>> >>> class Address(ModelBase, Base): >>> __tablename__ = 'addresses' >>> >>> id = Column(Integer, primary_key=True) >>> >>> user_id = Column(Integer, ForeignKey('users.id')) >>> >>> user = relationship("User", back_populates="addresses") >>> >>> >>> engine = create_engine('sqlite:///:memory:', echo=False) >>> Base.metadata.create_all(engine) >>> >>> Session = sessionmaker(bind=engine) >>> session = Session() >>> >>> jack = User.create(session) >>> jack.addresses.append(Address.create(session)) >>> >>> ----------------- >>> ----------------- >>> I have tested the code with SQLAlchemy for 1.3.18 and 1.4.0b1. I'm using >>> python 3.9.1 >>> >>> When I rewrite the last few lines a bit the warning disappears. For >>> instance: >>> >>> jack = User.create(session) >>> a = Address.create(session) >>> jack.addresses.append(a) >>> >>> >>> Any insight is appreciated. I'm still learning. >>> >>> Thanks, >>> Christian >>> >>> >>> >>> -- >>> 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 view this discussion on the web visit >>> https://groups.google.com/d/msgid/sqlalchemy/7a369ff7-659c-4ee4-a8d0-a786ec3579aen%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/sqlalchemy/7a369ff7-659c-4ee4-a8d0-a786ec3579aen%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/ba9d2326-976f-4418-bb92-f5e120fd3f52n%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/ba9d2326-976f-4418-bb92-f5e120fd3f52n%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/1e5ff83b-d483-4b62-864d-8d2f85c9acb6%40www.fastmail.com.