Reg. persisting data in ZODB via forms
Hello all, I am using zope.formlib.form package for my forms, when overriding the 'createAndAdd' method of form.AddForm I don't explicitly do the zope.event.notify(ObjectCreatedEvent(..)) call. I just add the data to self.context and it gets added (persisted) in the ZODB. But when I extend the form.EditForm in order to implement my own "Apply" action method, just calling the form.applyData or form.applyChanges doesn't persist the data. zope.event.notify(ObjectModifiedEvent(..)) call is needed in order to persist data. If someone could explain on this or point me to some documentation relating to this would be very helpful to me. Thank you Regards -- Joshua Immanuel HiPro IT Solutions Private Limited http://hipro.co.in
Hi Joshua, Am 08.06.2011, 10:34 Uhr, schrieb Joshua Immanuel <josh@hipro.co.in>:
Hello all, I am using zope.formlib.form package for my forms, when overriding the 'createAndAdd' method of form.AddForm I don't explicitly do the zope.event.notify(ObjectCreatedEvent(..)) call. I just add the data to self.context and it gets added (persisted) in the ZODB.
Persistence is handled by the transaction management and is IIRC independent of the notifications system. Nevertheless, not calling the events is not advisable.
But when I extend the form.EditForm in order to implement my own "Apply" action method, just calling the form.applyData or form.applyChanges doesn't persist the data. zope.event.notify(ObjectModifiedEvent(..)) call is needed in order to persist data.
If someone could explain on this or point me to some documentation relating to this would be very helpful to me.
From memory I can recall something similar related to making changes to copies of instance attributes but failing to apply them to attributes and needing to specifically go context.attribute = form_result for the changes to persist. Charlie -- Charlie Clark Managing Director Clark Consulting & Research German Office Helmholtzstr. 20 Düsseldorf D- 40215 Tel: +49-211-600-3657 Mobile: +49-178-782-6226
Hello Charlie, On Wed, 2011-06-08 at 10:48 +0200, Charlie Clark wrote:
From memory I can recall something similar related to making changes to copies of instance attributes but failing to apply them to attributes and needing to specifically go context.attribute = form_result for the changes to persist.
Supposing, we have a form action like: @form.action('Apply') def handle_edit(self, action, data): self.context.name += "Blah" This change is visible in subsequent requests. i.e if we view this object via another form, we can see the modification. However, if we restart the server (bluebream), this change is lost. The same thing happens when we use "form.applyData". If we 'notify' ObjectModifiedEvent, this does not happen. Since the object's modification is visible across requests, I am assuming that the transaction mechanism 'did' apply the changes to the object. But, it did not get to the disk :-/ -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
Hi Joe, Am 08.06.2011, 11:05 Uhr, schrieb Joe Steeve <js@hipro.co.in>:
Supposing, we have a form action like: @form.action('Apply') def handle_edit(self, action, data): self.context.name += "Blah"
This change is visible in subsequent requests. i.e if we view this object via another form, we can see the modification. However, if we restart the server (bluebream), this change is lost. The same thing happens when we use "form.applyData". If we 'notify' ObjectModifiedEvent, this does not happen.
Since the object's modification is visible across requests, I am assuming that the transaction mechanism 'did' apply the changes to the object.
But, it did not get to the disk :-/
I'm surprised at this but I'm not familiar with Bluebream's transactional processing. The quickest thing to do is to reenable notification and add a debug so that you can follow all the subscription calls and see what you need to call. Why do want to disable notification? Charlie -- Charlie Clark Managing Director Clark Consulting & Research German Office Helmholtzstr. 20 Düsseldorf D- 40215 Tel: +49-211-600-3657 Mobile: +49-178-782-6226
Hello Charlie, On Wed, 2011-06-08 at 11:16 +0200, Charlie Clark wrote:
I'm surprised at this but I'm not familiar with Bluebream's transactional processing. The quickest thing to do is to reenable notification and add a debug so that you can follow all the subscription calls and see what you need to call.
How do we get the list of subscribers for a particular event?
Why do want to disable notification?
We dont want to disable notification. We are just trying to understand how zope.formlib works. We were of the understanding that every 'request' starts and ends a transaction automatically (somewhere). So, seeing this explicit notify() confused us. Note that adding a new object does not require this explicit notify(). Further, if we have to expect the developer to manually notify after every change, it could invite unnecessary bugs. We are killing the server with a "Ctrl-C". Maybe something is not getting flushed out to the disk yet? -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
On Wed, 2011-06-08 at 15:01 +0530, Joe Steeve wrote:
We are killing the server with a "Ctrl-C". Maybe something is not getting flushed out to the disk yet?
Tried this with "--daemon" and "--stop-daemon" to paster. Still no change. So, this is not an issue. -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
Am 08.06.2011, 11:31 Uhr, schrieb Joe Steeve <js@hipro.co.in>:
How do we get the list of subscribers for a particular event?
By checking the registry for all adapters registered. from zope.component import queryAdapter queryAdapter(object, interface) ... # check the syntax and make sure you have the registry loaded.
Why do want to disable notification?
We dont want to disable notification. We are just trying to understand how zope.formlib works. We were of the understanding that every 'request' starts and ends a transaction automatically (somewhere). So, seeing this explicit notify() confused us. Note that adding a new object does not require this explicit notify().
The transactional stuff does not happen in zope.formlib. Unfortunately zope.formlib is a bit opaque in the way it works.
Further, if we have to expect the developer to manually notify after every change, it could invite unnecessary bugs.
Which is why you should let the library handle this for you wherever possible and something you write tests for.
We are killing the server with a "Ctrl-C". Maybe something is not getting flushed out to the disk yet?
No, that is not likely to be the case. Charlie -- Charlie Clark Managing Director Clark Consulting & Research German Office Helmholtzstr. 20 Düsseldorf D- 40215 Tel: +49-211-600-3657 Mobile: +49-178-782-6226
On Wed, 2011-06-08 at 11:40 +0200, Charlie Clark wrote:
Further, if we have to expect the developer to manually notify after every change, it could invite unnecessary bugs.
Which is why you should let the library handle this for you wherever possible and something you write tests for.
The problem is when we have to add multiple actions to a form, and each of them modify the object in different ways (say). In such a case, we cannot use the form.EditForm as is. We need to add more actions explicitly. And, if we have to notify(IObjectModifiedEvent) everytime, for the object to be persisted, it does not seem nice. I would have been happy if the transaction failed completely. But, it had not. The transaction was successful. Subsequent requests on the same object show that the previous modifications are intact. The object's changes just did not make it to the disk. -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
On Wed, 2011-06-08 at 15:23 +0530, Joe Steeve wrote:
I would have been happy if the transaction failed completely. But, it had not. The transaction was successful. Subsequent requests on the same object show that the previous modifications are intact. The object's changes just did not make it to the disk.
Found the issue. The problem was with our code. The content class was not derived from persistent.Persistent. Fixing that fixed the problem. Thanks guys :) -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
On 8 June 2011 10:05, Joe Steeve <js@hipro.co.in> wrote:
Hello Charlie,
On Wed, 2011-06-08 at 10:48 +0200, Charlie Clark wrote:
From memory I can recall something similar related to making changes to copies of instance attributes but failing to apply them to attributes and needing to specifically go context.attribute = form_result for the changes to persist.
Supposing, we have a form action like:
@form.action('Apply') def handle_edit(self, action, data): self.context.name += "Blah"
This change is visible in subsequent requests. i.e if we view this object via another form, we can see the modification. However, if we restart the server (bluebream), this change is lost. The same thing happens when we use "form.applyData". If we 'notify' ObjectModifiedEvent, this does not happen.
Since the object's modification is visible across requests, I am assuming that the transaction mechanism 'did' apply the changes to the object.
But, it did not get to the disk :-/
This looks like self.context is not an instance of a Persistent subclass. Only Persistent subclasses know how to register their changes with the ZODB. You see the change on subsequent requests because the object remains in the object cache, as soon as it's parent Persistent instance is invalidated, or the server restarted the changes will disappear. Storing mutable non-persistent objects in the ZODB requires some care, specifically you need to register the change on the object's persistent parent. The easiest way to do this is to assign it to the parent again, e.g. parent['child-name'] = child. My guess is that the ObjectModifiedEvent is dispatched to your object's parent and causes something to change there, with the side effect of storing your updated object. Laurence
As I mentioned on a follow-up post, we figured the 'Persistent' part. :) On Wed, 2011-06-08 at 13:29 +0100, Laurence Rowe wrote:
My guess is that the ObjectModifiedEvent is dispatched to your object's parent and causes something to change there, with the side effect of storing your updated object.
Even if the object's parent (a btree-container) had changed, will it attempt to force-store its entire child-tree? I am trying to imagine the effect of it on a huge tree. -- Joe Steeve HiPro IT Solutions Pvt. Ltd. http://hipro.co.in/
On Wed, Jun 08, 2011 at 06:20:26PM +0530, Joe Steeve wrote:
As I mentioned on a follow-up post, we figured the 'Persistent' part. :)
On Wed, 2011-06-08 at 13:29 +0100, Laurence Rowe wrote:
My guess is that the ObjectModifiedEvent is dispatched to your object's parent and causes something to change there, with the side effect of storing your updated object.
Even if the object's parent (a btree-container) had changed, will it attempt to force-store its entire child-tree? I am trying to imagine the effect of it on a huge tree.
The smallest unit that is ever written to a ZODB is one persistent object (with all its nonpersistent attributes/items, recursively). BTrees use multiple persistent buckets for their state and are very efficient, storage-wise. But this only matters when you're adding/removing items to a BTree. If you're modifying a persistent object stored in a BTree, the BTree itself remains unmodified and does not need to be re-written Marius Gedminas -- Linux became only possible because 20 years of OS research was carefully studied, analyzed, discussed and thrown away. -- Ingo Molnar
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 06/08/2011 01:40 PM, Marius Gedminas wrote:
On Wed, Jun 08, 2011 at 06:20:26PM +0530, Joe Steeve wrote:
As I mentioned on a follow-up post, we figured the 'Persistent' part. :)
On Wed, 2011-06-08 at 13:29 +0100, Laurence Rowe wrote:
My guess is that the ObjectModifiedEvent is dispatched to your object's parent and causes something to change there, with the side effect of storing your updated object.
Even if the object's parent (a btree-container) had changed, will it attempt to force-store its entire child-tree? I am trying to imagine the effect of it on a huge tree.
The smallest unit that is ever written to a ZODB is one persistent object (with all its nonpersistent attributes/items, recursively).
BTrees use multiple persistent buckets for their state and are very efficient, storage-wise. But this only matters when you're adding/removing items to a BTree. If you're modifying a persistent object stored in a BTree, the BTree itself remains unmodified and does not need to be re-written
Likewise, if you modify a non-persistent attribute of a persistent object which also has some attributes which are themselves persistent, only that object is re-written. Tres. - -- =================================================================== Tres Seaver +1 540-429-0999 tseaver@palladion.com Palladion Software "Excellence by Design" http://palladion.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk3vtXcACgkQ+gerLs4ltQ6fMQCfcdevBmf4yA3HBnZal/8map5h q2sAnj7acU3CjN2DACvCA2Ij213VvW/k =w9IP -----END PGP SIGNATURE-----
participants (6)
-
Charlie Clark -
Joe Steeve -
Joshua Immanuel -
Laurence Rowe -
Marius Gedminas -
Tres Seaver