Thank, I haven't yet figured out how to make your code more general
(without having to specify 'user_id'), but I think it can be done.

In the meantime I came up with a somewhat gross solution of my own.
The idea is to declare relation as `viewonly=True` and to delegate sets
to an injected write-only relationship (injection is the gross part).
I'm curious to hear your opinion on this approach, if possible.

Here is the code:
 

>
> from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
> from sqlalchemy import create_engine, and_
> from sqlalchemy import event
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.orm import relationship, mapper
> from sqlalchemy.orm import sessionmaker
>
>
> Base = declarative_base()
> engine = create_engine('sqlite:///:memory:', echo=False)
> Session = sessionmaker(bind=engine)
>
>
> def soft_deleting_relationship(target, primaryjoin):
>     assert issubclass(target, Base)
>     rel = relationship(target,
>                        primaryjoin=primaryjoin,
>                        viewonly=True,
>                        uselist=False,
>                        )
>
>     @event.listens_for(mapper, 'after_configured', once=True)
>     def configure():
>
>         key = '_all_child_' + rel.key
>         parent = rel.parent.class_
>         if not hasattr(parent, key):
>             setattr(parent, key, relationship(target, lazy="noload"))
>
>         @event.listens_for(rel, 'set', active_history=True)
>         def set(target, value, oldvalue, initiator):
>             if oldvalue is not None:
>                 oldvalue.delete()
>             getattr(target, key).append(value)
>
>     return rel
>
>
> class User(Base):
>     __tablename__ = 'users'
>
>     id = Column(Integer, primary_key=True)
>
>
> class Address(Base):
>     __tablename__ = 'addresses'
>     id = Column(Integer, primary_key=True)
>     email = Column(String, nullable=False)
>     deleted = Column(Boolean, nullable=False, default=False)
>
>     user_id = Column('user_id', Integer, ForeignKey('users.id'))
>
>     def delete(self):
>         self.deleted = True
>
>
> User.address = soft_deleting_relationship(
>     Address,
>     primaryjoin=lambda: and_(Address.user_id == User.id,
>                              ~Address.deleted),
> )
>
>
> def test():
>     Base.metadata.create_all(engine)
>     sess = Session()
>
>     a1 = Address(email='foo')
>     u = User(id=1, address=a1)
>     sess.add_all([u, a1])
>     sess.commit()
>
>     a2 = Address(email='bar')
>     u.address = a2
>     sess.commit()
>
>     assert a1.user_id == 1, a1.user_id
>     assert u.address.id == a2.id
>     assert a2.id is not None
>     assert a1.deleted
>
>
> test()
>
>
>

-- 
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.

Reply via email to