Ok, copied to https://bitbucket.org/zzzeek/sqlalchemy/issues/3941
W dniu piątek, 17 marca 2017 15:34:11 UTC+1 użytkownik Mike Bayer napisał:
that's not a bad idea at all can you transfer this to a bug report at
https://bitbucket.org/zzzeek/sqlalchemy/issues?status=new&status=open
<https://bitbucket.org/zzzeek/sqlalchemy/issues?status=new&status=open>
?
that would be helpful.
On 03/17/2017 09:11 AM, bartwo...@gmail.com <javascript:> wrote:
> I've run into autoflush issue while using AssociationProxy with
> sqlalchemy-1.1.6. Appending to association list fails, because
object is
> flushed before it is appended (and appending sets primary key
value). I
> can avoid it with session.no_autoflush context manager, but I
wonder if
> it's not worth slightly changing proxy behaviour to make it work with
> autoflush enabled.
>
> Minimal example of this issue below:
>
> |
> engine =engine_from_config(CONFIG)
> DBSession=scoped_session(sessionmaker())
> DBSession.configure(bind=engine)
> Base=declarative_base()
>
>
> classUserAlias(Base):
> __tablename__ ='user_aliases'
> user_id =Column(Integer,ForeignKey('user.id
<http://user.id>'),primary_key=True)
> alias_id =Column(Integer,ForeignKey('aliases.id
<http://aliases.id>'),primary_key=True)
> valid =Column(Boolean)
>
>
alias=relationship('Alias',backref=backref('user_assocs',uselist=False))
> user =relationship('User',backref=backref('alias_assocs'))
>
> def__init__(self,alias,valid=True):
> self.alias=alias
> self.valid =valid
>
>
> classAlias(Base):
> __tablename__ ='aliases'
> id =Column(Integer,primary_key=True)
> name =Column('name',String(64))
>
> user =association_proxy('user_assocs','user')
>
> def__init__(self,name):
> self.name <http://self.name> =name
>
>
> classUser(Base):
> __tablename__ ='user'
> id =Column(Integer,primary_key=True)
> name =Column(String(64))
>
> aliases =association_proxy('alias_assocs','alias')
>
> def__init__(self,name):
> self.name <http://self.name> =name
>
>
> deftest_assoc():
> user =User(name='John')
> DBSession.add(user)
> DBSession.commit()
>
> johny =Alias(name='Johny')
> user.aliases.append(johny)
> DBSession.commit()
>
> jan =Alias(name='Jan')
> DBSession.add(jan) # in my real use case proxied object is
already
> attached to session before appending, here I simulate it with
DBSession.add
> user.aliases.append(jan) # autoflush fails here
>
> DBSession.commit()
> returnuser
> |
>
> and stacktrace:
>
> |
>
/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/sql/crud.py:692:SAWarning:Column'user_aliases.user_id'ismarked
> asa member of the primary key fortable 'user_aliases',but has
> noPython-side orserver-side defaultgenerator indicated,nor does it
> indicate 'autoincrement=True'or'nullable=True',andnoexplicitvalue
> ispassed. Primarykey columns typically may notstore NULL.Notethat
asof
> SQLAlchemy1.1,'autoincrement=True'must be indicated explicitly
> forcomposite (e.g.multicolumn)primary keys
> ifAUTO_INCREMENT/SERIAL/IDENTITY behavior isexpected forone of the
> columns inthe primary key.CREATE TABLE statements are impacted
> bythischange aswell on most backends.
> util.warn(msg)
> Traceback(most recent call last):
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 1182,in_execute_context
> context)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/default.py",line
> 470,indo_execute
> cursor.execute(statement,parameters)
> psycopg2.IntegrityError:nullvalue incolumn "user_id"violates
> not-nullconstraint
> DETAIL: Failingrow contains (null,50,t).
>
>
> Theabove exception was the direct cause of the following exception:
>
> Traceback(most recent call last):
>
File"/home/bartek/dev/sqlalchemy-test/sqlalchemy_test/models.py",line
> 111,in<module>
> test_assoc()
>
File"/home/bartek/dev/sqlalchemy-test/sqlalchemy_test/models.py",line
> 105,intest_assoc
> user.aliases.append(jan)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/ext/associationproxy.py",line
> 610,inappend
> self.col.append(item)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/ext/associationproxy.py",line
> 509,in<lambda>
> col =property(lambdaself:self.lazy_collection())
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/ext/associationproxy.py",line
> 467,in__call__
> returngetattr(obj,self.target)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/attributes.py",line
> 237,in__get__
> returnself.impl.get(instance_state(instance),dict_)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/attributes.py",line
> 584,inget
> value =self.callable_(state,passive)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/strategies.py",line
> 557,in_load_for_state
> returnself._emit_lazyload(session,state,ident_key,passive)
> File"<string>",line 1,in<lambda>
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/strategies.py",line
> 635,in_emit_lazyload
> result =q.all()
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/query.py",line
> 2679,inall
> returnlist(self)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/query.py",line
> 2830,in__iter__
> self.session._autoflush()
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/session.py",line
> 1375,in_autoflush
> util.raise_from_cause(e)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/compat.py",line
> 203,inraise_from_cause
> reraise(type(exception),exception,tb=exc_tb,cause=cause)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/compat.py",line
> 187,inreraise
> raisevalue
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/session.py",line
> 1365,in_autoflush
> self.flush()
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/session.py",line
> 2139,inflush
> self._flush(objects)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/session.py",line
> 2259,in_flush
> transaction.rollback(_capture_exception=True)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py",line
> 60,in__exit__
> compat.reraise(exc_type,exc_value,exc_tb)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/compat.py",line
> 187,inreraise
> raisevalue
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/session.py",line
> 2223,in_flush
> flush_context.execute()
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py",line
> 389,inexecute
> rec.execute(self)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py",line
> 548,inexecute
> uow
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py",line
> 181,insave_obj
> mapper,table,insert)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py",line
> 835,in_emit_insert_statements
> execute(statement,params)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 945,inexecute
> returnmeth(self,multiparams,params)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/sql/elements.py",line
> 263,in_execute_on_connection
> returnconnection._execute_clauseelement(self,multiparams,params)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 1053,in_execute_clauseelement
> compiled_sql,distilled_params
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 1189,in_execute_context
> context)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 1393,in_handle_dbapi_exception
> exc_info
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/compat.py",line
> 203,inraise_from_cause
> reraise(type(exception),exception,tb=exc_tb,cause=cause)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/util/compat.py",line
> 186,inreraise
> raisevalue.with_traceback(tb)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/base.py",line
> 1182,in_execute_context
> context)
>
>
File"/home/bartek/envs/sqlalchemy-test/lib/python3.5/site-packages/sqlalchemy/engine/default.py",line
> 470,indo_execute
> cursor.execute(statement,parameters)
> sqlalchemy.exc.IntegrityError:(raised asa result of Query-invoked
> autoflush;consider usinga session.no_autoflush block ifthisflush
> isoccurring prematurely)(psycopg2.IntegrityError)nullvalue incolumn
> "user_id"violates not-nullconstraint
> DETAIL: Failingrow contains (null,50,t).
> [SQL:'INSERT INTO user_aliases (alias_id, valid) VALUES
(%(alias_id)s,
> %(valid)s)'][parameters:{'alias_id':50,'valid':True}]
> |
>
> Autoflush occurs in _AssociationList append method:
>
> |
> defappend(self,value):
> item =self._create(value)
> self.col.append(item)
> |
>
> If _create was called before self.col is evaluted created object
would
> not be autoflushed prematurely. Maybe it is worth changing it if
it does
> not break anything else.
>
> --
> 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
<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+...@googlegroups.com <javascript:>
> <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>.
> To post to this group, send email to sqlal...@googlegroups.com
<javascript:>
> <mailto:sqlal...@googlegroups.com <javascript:>>.
> Visit this group at https://groups.google.com/group/sqlalchemy
<https://groups.google.com/group/sqlalchemy>.
> For more options, visit https://groups.google.com/d/optout
<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
<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.