Thank you for the comprehensive answer. Without going too much into 
details, I have a table where file associated with each database record, 
and the name of that file is based on object id. This is what's happening 
now when I'm doing an INSERT:
1. Model instance is created
2. Explicit flush is done to get the id
3. File is created, the id is used for its name
4. Filename is written back to the instance
5. Commit

It works perfectly, but I would like to avoid explicit flushing and do all 
that file creating stuff somewhere implicitly before commit. This code is 
used inside the library so the solution should be database-specifics 
tolerant as much as possible too.

Actually, I'm starting to realize that refresh_flush event is not very good 
for this task, because it's called from within the flushing process and all 
object modifications remain ignored, so I cannot write the filename to the 
object from the event handler. What I need is the event that hooks to the 
model class, happens before commit, when the flush is already done, but I 
can modify the object and trigger another flush on exit if the object has 
been indeed modified. Is there anything like this in current SQLAlchemy?


On Friday, July 29, 2016 at 5:35:01 PM UTC+3, Mike Bayer wrote:
>
> Thanks for the great test case and this would be appropriate to be 
> posted as a bug, since it is a complete description. 
>
> So, the reason the primary key is not included right now is because 
> primary keys are populated in many different ways on the object, meaning 
> if your code relies upon refresh_flush(), it will break if you switch to 
> another database, or use an old version of Postgresql that doesn't 
> support RETURNING, or the table/dialect is set up to no longer use 
> RETURNING, etc.   The primary key is not actually populated at that 
> point the way the other defaults are (it was already populated 
> previously, so I guess to the event consumer, it doesn't make that much 
> difference). 
>
> Looking at where refresh_flush is called, there is still inconsistency 
> for other kinds of defaults too; if you use eager_defaults with a MySQL 
> database and server-side defaults it looks like you'd get called in the 
> ordinary refresh() event anyway (that is, if you try to eager_defaults 
> against a server_default="0", a Postgresql DB will call refresh_flush, a 
> MySQL DB will call refresh()). 
>
> Still, a primary key that's an autoincrement will never come back for 
> MySQL within either of these events - there's no RETURNING for MySQL 
> (and others). 
>
> refresh_flush() is very new and not widely used and it is likely 
> harmless to just add what we have here (not to mention document it 
> either way).  But for any change I'd first ask, what are you trying to 
> do?   The primary keys are excluded from "refresh" because they are not 
> usually a part of that concept, primary keys are "first class" and 
> always get pulled no matter what, you can grab them in after_insert(), 
> for example. 
>
>
>
>
>
> On 07/29/2016 04:25 AM, Lenar Imamutdinov wrote: 
> > Hello! 
> > 
> > Looks like the refresh_flush event is not triggered when the only field 
> > to update after flush is the primary key fed from RETURNING clause. 
> > However it should, as far as I understand what is mentioned in the 
> > documentation. 
> > 
> > Environment: SQLAlchemy 1.0.14, PostgreSQL 9.5, Python 3.4 
> > 
> > Here is how to reproduce this problem: 
> > 
> >     from sqlalchemy.ext.declarative import declarative_base 
> >     from sqlalchemy import Column, Integer 
> >     from sqlalchemy import create_engine 
> >     from sqlalchemy.orm import Session 
> >     from sqlalchemy import event 
> > 
> >     Base = declarative_base() 
> > 
> >     def receive_refresh_flush(target, context, attrs): 
> >         print('refresh_flush received') 
> > 
> >     class Test(Base): 
> >         __tablename__ = 'refresh_flush_test' 
> >         id = Column(Integer, primary_key=True) 
> >         # uncomment the field below to receive the event 
> >         # dummy = Column(Integer, default=0) 
> > 
> >     engine = create_engine('postgresql://test:test@localhost:5432/test') 
> >     Base.metadata.create_all(engine) 
> >     session = Session(engine) 
> > 
> >     event.listen(Test, 'refresh_flush', receive_refresh_flush) 
> > 
> >     obj = Test() 
> >     session.add(obj) 
> >     session.commit() 
> > 
> > -- 
> > 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. 
> > 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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to