Hello all,
Short summary of my question:
Is it possible to stop rollback() from expiring dirty objects?
Specifically, in the case where there are
- local changes made outside to mapped objects outside of a transaction
- flush() is called
- the flush fails
In this case SQLAlchemy will expire any objects that had local changes, and
those changes are lost. I would ideally like get objects & session to be in
the same state as they were before I called flush().
Longer explanation of my approach, in case I am just doing it wrong :)
I have a GUI application where users can load, view, and edit some database
mapped objects. Stripped down, it's pretty simple stuff like this:
class Action(Base):
__tablename__ = "action"
id = Column(Integer, primary_key=True)
description = Column(Text)
class Step(Base, ActionSchemaMixin):
__tablename__ = "step"
id = Column(Integer, primary_key=True)
id_action = Column(Integer, ForeignKey(Action.id))
action = relationship(Action, backref='steps')
So the action has some attributes, and a number of steps, which have their
own attributes. Users can select an action (or create a new one) - then
add, remove, and update steps for that action from the GUI.
I have found it to be an extremely useful pattern to couple these widgets
directly to the mapped objects they are dealing with, and let the various
event handlers to update the mapped objects whenever the user alters the
GUI.
The following pseudo-code should give you an idea
class ActionWidget(Widget):
def __init__(action):
self.action = action
self.description_edit_widget = TextEditWidget(on_changed=self.
on_description_widget_changed)
def on_description_widget_changed(self, new_description):
self.action.description = new_description
I also have a widget for a list-of-steps that shows a summary for each, and
allows you to add/remove new ones - and a widget for editing an individual
step.
Because I have no control over how long the user will faff about when
editing one of these actions, and we do not want long open transactions to
the database, I have set up my session with the slightly controversial
(autoflush=False, autocommit=True, expire_on_commit=False) options. I load
up the action and all the steps, the user can take as long as they like
mucking about with it - and when they press the 'Save' button, I just flush
all the changes.
It works great, except if something goes wrong with the flushing. If some
DB constraint is violated for example, the transaction created in flush()
is rolled back. All my modified objects are expired, and any new ones are
expunged, as faithfully described in the docs.
In this case though, it is unfortunate, because now I have a mismatch
between what is in my GUI and the objects they are supposed to be
displaying. I want to be able to warn my user about the problem and let
them fix the one field that was wrong, without forcing them to loose all
their changes and start again.
It is quite difficult for me to recreate the mapped objects changed state
from the GUI elements alone, as there are temporary widgets created at
times to edit certain attributes.
The only way around this that I can think of is to detach all the objects
before coupling them to the GUI elements - then in my save function,
somehow copying all of the updated/new objects before adding them to a
session and attempting to commit the changes. I could get this to work, but
think it might be fiddly when there are a mixture of new and dirty
persisted objects.
Interestingly when creating a set of brand new objects, things are fine too
- although they are expunged, they can be re-added to the session when the
user is ready to try again.
hoping there is a simple answer but suspecting there isn't :)
All the best,
Philip
--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.