On 11/05/2016 08:45 PM, Yegor Roganov wrote:
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.


it looks like recipes I wrote before we had decent events in place, it's fine.



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
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto: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.

Reply via email to