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.



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

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