Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

fix merge conflicts

  • Loading branch information...
commit 46c0fdea9ca4fec6d61f40a5291378c6e0053b77 2 parents fd774f7 + 0f9995e
Erik Janssens authored
14 camelot/admin/application_admin.py
View
@@ -151,6 +151,7 @@ def __init__(self):
# Cache created ObjectAdmin objects
#
self._object_admin_cache = {}
+ self._memento = None
def register(self, entity, admin_class):
"""Associate a certain ObjectAdmin class with another class. This
@@ -187,6 +188,19 @@ def get_settings( self ):
settings = QtCore.QSettings()
settings.beginGroup( 'Camelot' )
return settings
+
+ def get_memento( self ):
+ """Returns an instance of :class:`camelot.core.memento.SqlMemento` that
+ can be used to store changes made to objects. Overwrite this method to
+ make it return `None` if no changes should be stored to the database, or
+ to return another instance if the changes should be stored elsewhere.
+
+ :return: `None` or an :class:`camelot.core.memento.SqlMemento` instance
+ """
+ from camelot.core.memento import SqlMemento
+ if self._memento == None:
+ self._memento = SqlMemento()
+ return self._memento
def get_application_admin( self ):
"""Get the :class:`ApplicationAdmin` class of this application, this
62 camelot/admin/entity_admin.py
View
@@ -29,11 +29,12 @@
from camelot.admin.action.list_action import OpenFormView
from camelot.admin.object_admin import ObjectAdmin
from camelot.view.model_thread import post, model_function
-from camelot.view.utils import to_string
+from camelot.view.utils import to_string
+from camelot.core.memento import memento_change
from camelot.core.utils import ugettext_lazy, ugettext
from camelot.admin.validator.entity_validator import EntityValidator
-from sqlalchemy import orm, exc
+from sqlalchemy import orm
class EntityAdmin(ObjectAdmin):
"""Admin class specific for classes that are mapped by sqlalchemy.
@@ -507,32 +508,22 @@ def delete(self, entity_instance):
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 already 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 Memento
- # only register the delete when the camelot model is active
- if hasattr(Memento, 'query'):
- from camelot.model.authentication import get_current_authentication
- history = Memento( model = unicode( self.entity.__name__ ),
- memento_type = 'before_delete',
- primary_key = pk,
- previous_attributes = {},
- authentication = get_current_authentication() )
- entity_instance.delete()
+ primary_key = self.primary_key( entity_instance )
+ if not None in primary_key:
+ # save the state before the update
+ memento = self.get_memento()
+ if memento != None:
+ modifications = dict()
+ change = memento_change( model = unicode( self.entity.__name__ ),
+ memento_type = 'before_delete',
+ primary_key = primary_key,
+ previous_attributes = modifications )
+ memento.register_changes( [change] )
+ session.delete( entity_instance )
session.flush( [entity_instance] )
- if history:
- Session.object_session( history ).flush( [history] )
@model_function
def expunge(self, entity_instance):
@@ -560,21 +551,14 @@ def flush(self, entity_instance):
# If needed, track the changes
#
primary_key = self.primary_key( entity_instance )
- if modifications and (primary_key != None) and len(primary_key)==1:
- from camelot.model.memento import Memento
- # only register the update when the camelot model is active
- if hasattr(Memento, 'query'):
- from camelot.model.authentication import get_current_authentication
- history = Memento( model = unicode( self.entity.__name__ ),
- memento_type = 'before_update',
- primary_key = primary_key[0],
- previous_attributes = modifications,
- authentication = get_current_authentication() )
-
- try:
- history.flush()
- except exc.DatabaseError, e:
- self.logger.error( 'Programming Error, could not flush history', exc_info = e )
+ if modifications and (None not in primary_key):
+ memento = self.get_memento()
+ if memento != None:
+ change = memento_change( model = unicode( self.entity.__name__ ),
+ memento_type = 'before_update',
+ primary_key = primary_key,
+ previous_attributes = modifications )
+ memento.register_changes( [change] )
@model_function
def refresh(self, entity_instance):
3  camelot/admin/object_admin.py
View
@@ -335,6 +335,9 @@ def get_settings( self ):
settings = self.app_admin.get_settings()
settings.beginGroup( self.get_name()[:255] )
return settings
+
+ def get_memento( self ):
+ return self.app_admin.get_memento()
def get_delete_mode(self):
return self.delete_mode
10 camelot/core/memento.py
View
@@ -28,8 +28,11 @@
import collections
import datetime
+import logging
-from sqlalchemy import func, sql, orm
+from sqlalchemy import func, sql, orm, exc
+
+LOGGER = logging.getLogger( 'camelot.core.memento' )
#
# lightweight data structure to present object changes to the memento
@@ -94,7 +97,10 @@ def register_changes( self,
if len( rows ):
table = self._get_memento_table()
clause = table.insert( creation_date = func.current_timestamp() )
- clause.execute( rows )
+ try:
+ clause.execute( rows )
+ except exc.DatabaseError, e:
+ LOGGER.error( 'Programming Error, could not flush history', exc_info = e )
def get_changes( self,
model,
9 camelot/model/memento.py
View
@@ -22,8 +22,13 @@
#
# ============================================================================
-"""Set of classes to keep track of changes to objects and be able to restore
-their state
+"""The ORM part of the classes that store the change history of objects to
+the database. The table defined here is used in :mod:`camelot.core.memento`
+to store the changes.
+
+To prevent this table to be used to store changes, overwrite the
+:meth:`camelot.admin.application_admin.ApplicationAdmin.get_memento` method
+the custom `ApplicationAdmin`.
"""
import datetime
2  doc/sphinx/source/doc/data_model.rst
View
@@ -4,7 +4,7 @@
Built in data models
########################
-Camelot comes with a number of built in data models. To avoid boiler platem odels needed in almost any application (like Persons, Addresses, etc.),
+Camelot comes with a number of built in data models. To avoid boiler plate models needed in almost any application (like Persons, Addresses, etc.),
the developer is encouraged to use these data models as a start for developing custom applications.
To activate a model, the model should be imported in the `setup_model` method of `settings.py`::
11 test/test_core.py
View
@@ -1,4 +1,6 @@
import unittest
+
+from camelot.core.memento import memento_change
from camelot.test import ModelThreadTestCase
memento_id_counter = 0
@@ -17,7 +19,6 @@ def setUp( self ):
self.model = 'TestMemento'
def test_lifecycle( self ):
- from camelot.core.memento import memento_change
memento_changes = [
memento_change( self.model,
@@ -37,6 +38,14 @@ def test_lifecycle( self ):
{} ) )
self.assertEqual( len(changes), 3 )
+ def test_no_error( self ):
+ memento_changes = [
+ memento_change( None,
+ [self.id_counter],
+ None, None ),
+ ]
+ self.memento.register_changes( memento_changes )
+
class ConfCase(unittest.TestCase):
"""Test the global configuration"""
Please sign in to comment.
Something went wrong with that request. Please try again.