Yes it recommends using ``no_autoflush`` and:

with DBSession.no_autoflush:
    dep1.users.append(user2)

fixes it.

So is this the correct way appending to the collection, and should I wrap
all code that is manipulating ``Department.users`` with a ``no_autoflush``?

Erkan Ozgur Yilmaz

On Thu, Nov 27, 2014 at 2:13 AM, Michael Bayer <mike...@zzzcomputing.com>
wrote:

> take a look at the stack trace (or send it along).  Do you see autoflush
> in it?  If so, you should use “with session.no_autoflush” around the area
> where you are likely triggering a lazy load of an attribute or collection.
>
>
> http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html#sqlalchemy.orm.session.Session.no_autoflush
>
>
> On Nov 26, 2014, at 6:00 PM, Erkan Özgür Yılmaz <eoyil...@gmail.com>
> wrote:
>
> As I understand it is not related with the __init__() methods or how I
> initialize the attributes
>
> Erkan Ozgur Yilmaz
>
> On Thu, Nov 27, 2014 at 12:58 AM, Erkan Özgür Yılmaz <eoyil...@gmail.com>
> wrote:
>
>> Ok my test case was not reproducing the error as in my previous post, but
>> consider this one it is generating the IntegrityError
>>
>> if __name__ == "__main__":
>>     database_engine_settings = {
>>         "sqlalchemy.url": "sqlite:///:memory:",
>>         "sqlalchemy.echo": False,
>>     }
>>
>>     engine = engine_from_config(database_engine_settings, 'sqlalchemy.')
>>     DBSession.configure(
>>         bind=engine,
>>         extension=None
>>     )
>>     Base.metadata.create_all(engine)
>>
>>     user1 = User()
>>     dep1 = Department(users=[user1])
>>     DBSession.add(user1)
>>     DBSession.add(dep1)
>>     DBSession.commit()
>>
>>     assert user1 in dep1.users
>>     assert dep1 in user1.departments
>>
>>     dep_users = DBSession.query(DepartmentUser).all()
>>     assert len(dep_users) == 1
>>
>>     # user2 = User(departments=[dep1])
>>     user2 = User()
>>     DBSession.add(user2)
>>     DBSession.commit()
>>
>>     dep1.users.append(user2)
>>
>>
>>
>> Erkan Ozgur Yilmaz
>>
>> On Thu, Nov 27, 2014 at 12:39 AM, Erkan Özgür Yılmaz <eoyil...@gmail.com>
>> wrote:
>>
>>> Hi,
>>>
>>> I've encountered a situation where I don't know if this is a bug or it
>>> is the correct behavior. It is about association_proxy. Please see the
>>> User.__init__ and Department.__init__ methods.
>>>
>>> from sqlalchemy import *
>>> from sqlalchemy.orm import *
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy.ext.associationproxy import association_proxy
>>>
>>>
>>> Base = declarative_base()
>>>
>>> DBSession = scoped_session(
>>>     sessionmaker(
>>>         extension=None
>>>     )
>>> )
>>>
>>>
>>> class Entity(Base):
>>>     __tablename__ = 'Entities'
>>>
>>>     id = Column(Integer, primary_key=True)
>>>     entity_type = Column(String(128), nullable=False)
>>>
>>>     __mapper_args__ = {
>>>         "polymorphic_on": entity_type,
>>>         "polymorphic_identity": "SimpleEntity"
>>>     }
>>>
>>>
>>> class User(Entity):
>>>     __tablename__ = 'Users'
>>>     __mapper_args__ = {"polymorphic_identity": "User"}
>>>     user_id = Column('id', Integer, ForeignKey('Entities.id'),
>>>                      primary_key=True)
>>>
>>>     departments = association_proxy(
>>>         'department_role',
>>>         'department',
>>>         creator=lambda d: DepartmentUsers(department=d)
>>>     )
>>>
>>>     department_role = relationship(
>>>         'DepartmentUser',
>>>         back_populates='user',
>>>         cascade='all, delete-orphan',
>>>         primaryjoin='Users.c.id 
>>> <http://users.c.id/>==Department_Users.c.uid'
>>>     )
>>>
>>>     def __init__(self, departments=None):
>>>         super(User, self).__init__()
>>>         if departments is None:
>>>             departments = []
>>>
>>>         # using this creates an auto flush and raises an IntegrityError
>>>         # self.departments = departments
>>>
>>>         # where as using this is OK
>>>         for department in departments:
>>>             self.department_role.append(
>>>                 DepartmentUser(user=self, department=department)
>>>             )
>>>
>>>
>>> class Department(Entity):
>>>     __tablename__ = 'Departments'
>>>     __mapper_args__ = {"polymorphic_identity": "Department"}
>>>     department_id = Column('id', Integer, ForeignKey('Entities.id'),
>>>                            primary_key=True)
>>>
>>>     users = association_proxy(
>>>         'user_role',
>>>         'user',
>>>         creator=lambda u: DepartmentUser(user=u)
>>>     )
>>>
>>>     user_role = relationship(
>>>         "DepartmentUser",
>>>         back_populates="department",
>>>         cascade='all, delete-orphan',
>>>         primaryjoin='Departments.c.id 
>>> <http://departments.c.id/>==Department_Users.c.did'
>>>     )
>>>
>>>     @validates('user_role')
>>>     def _validate_user_role(self, key, user_role):
>>>         """validates the given user_role variable
>>>         """
>>>         return user_role
>>>
>>>     def __init__(self, users=None):
>>>         if users is None:
>>>             users = []
>>>         # again using this creates an auto flush and raises an 
>>> IntegrityError
>>>         # self.users = users
>>>
>>>         # where as using this is OK
>>>         for user in users:
>>>             self.user_role.append(
>>>                 DepartmentUser(department=self, user=user)
>>>             )
>>>
>>>
>>> class Role(Entity):
>>>     __tablename__ = 'Roles'
>>>     __mapper_args__ = {"polymorphic_identity": "Role"}
>>>     role_id = Column('id', Integer, ForeignKey('Entities.id'), 
>>> primary_key=True)
>>>
>>>
>>> class DepartmentUser(Base):
>>>     __tablename__ = 'Department_Users'
>>>
>>>     user_id = Column(
>>>         'uid',
>>>         Integer,
>>>         ForeignKey('Users.id'),
>>>         primary_key=True
>>>     )
>>>
>>>     user = relationship(
>>>         'User',
>>>         back_populates='department_role',
>>>         primaryjoin='DepartmentUser.user_id==User.user_id'
>>>     )
>>>
>>>     department_id = Column(
>>>         'did',
>>>         Integer,
>>>         ForeignKey('Departments.id'),
>>>         primary_key=True
>>>     )
>>>
>>>     department = relationship(
>>>         'Department',
>>>         back_populates='user_role',
>>>         primaryjoin='DepartmentUser.department_id==Department.department_id'
>>>     )
>>>
>>>     role_id = Column(
>>>         'rid',
>>>         Integer,
>>>         ForeignKey('Roles.id'),
>>>         nullable=True
>>>     )
>>>
>>>     role = relationship(
>>>         'Role',
>>>         primaryjoin='DepartmentUser.role_id==Role.role_id'
>>>     )
>>>
>>>     def __init__(self, department=None, user=None, role=None):
>>>         self.department = department
>>>         self.user = user
>>>         self.role = role
>>>
>>>
>>> if __name__ == "__main__":
>>>     database_engine_settings = {
>>>         "sqlalchemy.url": "sqlite:///:memory:",
>>>         "sqlalchemy.echo": False,
>>>     }
>>>
>>>     engine = engine_from_config(database_engine_settings, 'sqlalchemy.')
>>>     DBSession.configure(
>>>         bind=engine,
>>>         extension=None
>>>     )
>>>     Base.metadata.create_all(engine)
>>>
>>>     user1 = User()
>>>     dep1 = Department()
>>>     DBSession.add(user1)
>>>     DBSession.add(dep1)
>>>     DBSession.commit()
>>>
>>>     dep1.users.append(user1)
>>>
>>>     assert user1 in dep1.users
>>>     assert dep1 in user1.departments
>>>
>>>     dep_users = DBSession.query(DepartmentUser).all()
>>>     assert len(dep_users) == 1
>>>
>>>     user2 = User()
>>>     dep1.users.append(user2)
>>>     DBSession.add(user2)
>>>     DBSession.commit()
>>>
>>> So, I get an IntegrityError if I set the **self.departments** or
>>> **self.users** directly, so apparently creating the association objects
>>> triggers an auto-flush but if I create the association objects instead of
>>> directly setting the attributes there is no error. I'm ready to use the
>>> work around of creating the association object but I'm also curious if this
>>> is a bug or normal way of using association_proxy.
>>>
>>> Thanks,
>>>
>>> Erkan Ozgur Yilmaz
>>>
>>
>>
>
> --
> 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 http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>
>
>  --
> 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 http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to