def delete(self, entity_instance): """Delete an entity instance""" from sqlalchemy.orm.session import Session session = Session.object_session(entity_instance) # # new and deleted instances cannot be deleted # if session: if entity_instance in session.new: session.expunge(entity_instance) elif (entity_instance not in session.deleted) and ( entity_instance in session ): # if the object is not in the session, it might allready be deleted history = None # # only if we know the primary key, we can keep track of its history # primary_key = self.mapper.primary_key_from_instance(entity_instance) # # we can only store history of objects where the primary key has only # 1 element # @todo: store history for compound primary keys # if not None in primary_key and len(primary_key) == 1: pk = primary_key[0] # save the state before the update from camelot.model.memento import BeforeDelete # only register the delete when the camelot model is active if hasattr(BeforeDelete, "query"): from camelot.model.authentication import getCurrentAuthentication history = BeforeDelete( model=unicode(self.entity.__name__), primary_key=pk, previous_attributes={}, authentication=getCurrentAuthentication(), ) entity_instance.delete() session.flush([entity_instance]) if history: Session.object_session(history).flush([history])
def delete(self, entity_instance): """Delete an entity instance""" from sqlalchemy.orm.session import Session session = Session.object_session(entity_instance) # # new and deleted instances cannot be deleted # if session: if entity_instance in session.new: session.expunge(entity_instance) elif (entity_instance not in session.deleted) and \ (entity_instance in session): # if the object is not in the session, it might allready be deleted history = None # # only if we know the primary key, we can keep track of its history # primary_key = self.mapper.primary_key_from_instance( entity_instance) # # we can only store history of objects where the primary key has only # 1 element # @todo: store history for compound primary keys # if not None in primary_key and len(primary_key) == 1: pk = primary_key[0] # save the state before the update from camelot.model.memento import BeforeDelete # only register the delete when the camelot model is active if hasattr(BeforeDelete, 'query'): from camelot.model.authentication import getCurrentAuthentication history = BeforeDelete( model=unicode(self.entity.__name__), primary_key=pk, previous_attributes={}, authentication=getCurrentAuthentication()) entity_instance.delete() session.flush([entity_instance]) if history: Session.object_session(history).flush([history])
def _handle_update_requests(self): # # Copy the update requests and clear the list of requests # locker = QtCore.QMutexLocker(self._mutex) update_requests = [u for u in self._update_requests] self._update_requests = [] locker.unlock() # # Handle the requests # for flushed, row, column, value in update_requests: attribute, field_attributes = self.getColumns()[column] from sqlalchemy.exceptions import DatabaseError from sqlalchemy import orm new_value = value() self.logger.debug( 'set data for row %s;col %s' % ( row, column ) ) if new_value == ValueLoading: return None o = self._get_object( row ) if not o: # the object might have been deleted from the collection while the editor # was still open self.logger.debug( 'this object is no longer in the collection' ) try: self.unflushed_rows.remove( row ) except KeyError: pass return old_value = getattr( o, attribute ) # # When the value is a related object, the related object might have changed # changed = ( new_value != old_value ) or ( field_attributes.get('embedded', False) and \ field_attributes.get('target', False)) # # In case the attribute is a OneToMany or ManyToMany, we cannot simply compare the # old and new value to know if the object was changed, so we'll # consider it changed anyway # direction = field_attributes.get( 'direction', None ) if direction in ( orm.interfaces.MANYTOMANY, orm.interfaces.ONETOMANY ): changed = True if changed: # update the model model_updated = False try: setattr( o, attribute, new_value ) # # setting this attribute, might trigger a default function to return a value, # that was not returned before # self.admin.set_defaults( o, include_nullable_fields=False ) model_updated = True except AttributeError, e: self.logger.error( u"Can't set attribute %s to %s" % ( attribute, unicode( new_value ) ), exc_info = e ) except TypeError: # type error can be raised in case we try to set to a collection pass if self.flush_changes and self.validator.isValid( row ): # save the state before the update try: self.admin.flush( o ) except DatabaseError, e: #@todo: when flushing fails, the object should not be removed from the unflushed rows ?? self.logger.error( 'Programming Error, could not flush object', exc_info = e ) locker.relock() try: self.unflushed_rows.remove( row ) except KeyError: pass locker.unlock() # # we can only track history if the model was updated, and it was # flushed before, otherwise it has no primary key yet # if model_updated and hasattr(o, 'id') and o.id: # # in case of images or relations, we cannot pickle them # if ( not 'Imag' in old_value.__class__.__name__ ) and not direction: from camelot.model.memento import BeforeUpdate # only register the update when the camelot model is active if hasattr(BeforeUpdate, 'query'): from camelot.model.authentication import getCurrentAuthentication history = BeforeUpdate( model = unicode( self.admin.entity.__name__ ), primary_key = o.id, previous_attributes = {attribute:old_value}, authentication = getCurrentAuthentication() ) try: history.flush() except DatabaseError, e: self.logger.error( 'Programming Error, could not flush history', exc_info = e )
def _handle_update_requests(self): # # Copy the update requests and clear the list of requests # locker = QtCore.QMutexLocker(self._mutex) update_requests = [u for u in self._update_requests] self._update_requests = [] locker.unlock() # # Handle the requests # for flushed, row, column, value in update_requests: attribute, field_attributes = self.getColumns()[column] from sqlalchemy.exceptions import DatabaseError from sqlalchemy import orm new_value = value() self.logger.debug('set data for row %s;col %s' % (row, column)) if new_value == ValueLoading: return None o = self._get_object(row) if not o: # the object might have been deleted from the collection while the editor # was still open self.logger.debug('this object is no longer in the collection') try: self.unflushed_rows.remove(row) except KeyError: pass return old_value = getattr(o, attribute) # # When the value is a related object, the related object might have changed # changed = ( new_value != old_value ) or ( field_attributes.get('embedded', False) and \ field_attributes.get('target', False)) # # In case the attribute is a OneToMany or ManyToMany, we cannot simply compare the # old and new value to know if the object was changed, so we'll # consider it changed anyway # direction = field_attributes.get('direction', None) if direction in (orm.interfaces.MANYTOMANY, orm.interfaces.ONETOMANY): changed = True if changed: # update the model model_updated = False try: setattr(o, attribute, new_value) # # setting this attribute, might trigger a default function to return a value, # that was not returned before # self.admin.set_defaults(o, include_nullable_fields=False) model_updated = True except AttributeError, e: self.logger.error(u"Can't set attribute %s to %s" % (attribute, unicode(new_value)), exc_info=e) except TypeError: # type error can be raised in case we try to set to a collection pass if self.flush_changes and self.validator.isValid(row): # save the state before the update try: self.admin.flush(o) except DatabaseError, e: #@todo: when flushing fails, the object should not be removed from the unflushed rows ?? self.logger.error( 'Programming Error, could not flush object', exc_info=e) locker.relock() try: self.unflushed_rows.remove(row) except KeyError: pass locker.unlock() # # we can only track history if the model was updated, and it was # flushed before, otherwise it has no primary key yet # if model_updated and hasattr(o, 'id') and o.id: # # in case of images or relations, we cannot pickle them # if (not 'Imag' in old_value.__class__.__name__ ) and not direction: from camelot.model.memento import BeforeUpdate # only register the update when the camelot model is active if hasattr(BeforeUpdate, 'query'): from camelot.model.authentication import getCurrentAuthentication history = BeforeUpdate( model=unicode(self.admin.entity.__name__), primary_key=o.id, previous_attributes={attribute: old_value}, authentication=getCurrentAuthentication()) try: history.flush() except DatabaseError, e: self.logger.error( 'Programming Error, could not flush history', exc_info=e)