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.