On Wednesday, March 23, 2011 1:40:30 AM UTC+1, Michael Bayer wrote:
>
>
> On Mar 22, 2011, at 6:03 PM, Debilski wrote:
>
> > Hi,
> > I’m having a problem with the collection append method in a many-to-
> > many relationship with association object. Basically, I’d like to
> > connect classes of type Entity through a Context object (which holds a
> > description of the connection type). Programmatically, it should go
> > like
> > 
> >  experiment = Entity()
> >  observer = Entity()
> >  experiment.connect("has Observer", observer)
> >  print experiment.connected # prints [observer]
> > 
> > However, what happens is that this code results in observer being
> > printed twice unless some other operation occurred before that
> > statement. It is not really clear to me why this happens. The code is
> > as follows:
>
> so when you append to a list, if multiple appends of the same object (same 
> identity) occur, you'll see those duplicated elements in the list as it is 
> in memory.  Once the session is committed, the attribute is expired - on a 
> load back, relational rules mean you can only get the element from a 
> one-to-many back once, so then you see it once.
>
> The element is duplicated because of this:
>
>     context = Context(back_referenced=self,
> connected=connection_object, connection_type=connection_type)
>            self.connections.append(context)
>
> Context(back_referenced=self) triggers an event based on the backref in the 
> "backreferenced" relationship that also appends the item to the "connected" 
> list.  The "connected.append" afterwards does the same thing a second time. 
>  "Context.back_referenced" and "Entity.connections" are two sides of the 
> same relational coin, and establishment via relationship/backref establishes 
> this behavior in memory pre-flush as well.
>

Thank you! Of course, when I specify the back_referenced manually, there is 
no need to use append. Seems pretty clear.

Cheers
/rike
 

> > 
> >    from sqlalchemy import Column, ForeignKey, String, Integer,
> > create_engine
> >    from sqlalchemy.orm import relationship, backref, scoped_session,
> > sessionmaker
> >    from sqlalchemy.ext.declarative import declarative_base
> >    Base = declarative_base()
> > 
> >    class Entity(Base):
> >        __tablename__ = "entities"
> >        id = Column('id', Integer, primary_key=True)
> > 
> >        def connect(self, connection_type, connection_object):
> >            """Connect this entity with connection_object via the
> > connection_type."""
> >            context = Context(back_referenced=self,
> > connected=connection_object, connection_type=connection_type)
> >            self.connections.append(context)
> > 
> >        @property
> >        def connected(self):
> >            return [c.connected for c in self.connections]
> > 
> > 
> >    class Context(Base):
> >        __tablename__ = "contexts"
> >        entity_id = Column('entity_id', Integer,
> > ForeignKey(Entity.id), primary_key=True)
> >        connected_id = Column('connected_id', Integer,
> > ForeignKey(Entity.id), primary_key=True)
> > 
> >        connection_type = Column('connection_type', String(500))
> > 
> >        # Each entity can have a context of related entities
> >        back_referenced = relationship(Entity,
> >            backref=backref('connections', cascade="all"),
> >            primaryjoin=entity_id==Entity.id)
> > 
> >        connected = relationship(Entity,
> >            backref=backref('back_references', cascade="all"),
> >            primaryjoin=connected_id==Entity.id)
> > 
> >        def __repr__(self):
> >            return "Context(entity_id={id!s}, connected_id={cid!s},
> > connection_type={type})".format(id=self.entity_id,
> > cid=self.connected_id, type=self.connection_type)
> > 
> >        def __str__(self):
> >            return "Context({e} has {t}
> > {c})".format(e=self.back_referenced, t=self.connection_type,
> > c=self.connected)
> > 
> >    session = scoped_session(sessionmaker(autocommit=True))
> >    engine = create_engine("sqlite://")
> >    session(bind=engine)
> >    Base.metadata.create_all(engine)
> > 
> >    e1 = Entity()
> >    e2 = Entity()
> > 
> >    session.add(e1)
> >    session.add(e2)
> > 
> >    e1.connect("C", e2)
> > 
> >    print e1.connected
> >    print "Number of connections to e1", len(e1.connected)
> > 
> > # prints:
> > # [<__main__.Entity object at 0x101613dd0>, <__main__.Entity object at
> > 0x101613dd0>]
> > # Number of connections to e1 2
> > 
> > Is there anything I can do to get the correct number of entities back?
> > 
> > Thanks
> > /rike
> > 
> > -- 
> > You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> > To post to this group, send email to sqlal...@googlegroups.com.
> > To unsubscribe from this group, send email to 
> sqlalchemy+...@googlegroups.com.
> > For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> > 
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to