There is documentation on using Python dict
with z3c.form
(loading & storing form data).
However, the z3c.form
datamanager
used for dicts is not registered for other types or interfaces (see reference ), whereas annotations typically use something like PersistentDict
.
How can I use the DictionaryField
datamanager
in this scenario? Ie. so that in my form's getContent
method I merely return the PersistentDict
annotation.
Well, unfortunately there seems no simple solution for this requirement. I once faced the same problem using the datagrid field in a z3c form.
The following instruction solves the problem for the datagrid field, which is a list
(PersistentList of dicts
(PersistentMappings).
I guess you may adapt this solution for your case.
First you need to add the following code to the getContent
method:
from plone.directives import form
class MyForm(form.SchemaEditForm):
schema = IMyFormSchema
ignoreContext = False
def getContent(self):
annotations = IAnnotations(self.context)
if ANNOTATION_KEY not in annotations:
annotations[ANNOTATION_KEY] = PersistentMapping()
return YourStorageConfig(annotations[ANNOTATION_KEY])
Important note: I wrap the annotation storage to satisfy the get/set behavior of the z3c form. Check the following YourStorageConfig
implementation and you will see why :-).
class YourStorageConfig(object):
implements(IMyFormSchema)
def __init__(self, storage):
self.storage = storage
def __getattr__(self, name):
if name == 'storage':
return object.__getattr__(self, name)
value = self.storage.get(name)
return value
def __setattr__(self, name, value):
if name == 'storage':
return object.__setattr__(self, name, value)
if name == 'yourfieldname':
self.storage[name] = PersistentList(map(PersistentMapping, value))
return
raise AttributeError(name)
yourfieldname
should be the field name you are using in the form schema.
To implement the a datagrid field, there is some more work to do, but this may be enough for your case.
Please post comments, or tracebacks, so I can provide further help. I'll gonna add more details/explanation if necessary ;-)
It turns out the answer is as easy as the following ZCML adapter registration:
<adapter
for="persistent.dict.PersistentDict zope.schema.interfaces.IField"
provides="z3c.form.interfaces.IDataManager"
factory="z3c.form.datamanager.DictionaryField"
/>
With that, the following customization of a form is sufficient to use ( PersistentDict
) annotations for loading & storing form data:
def getContent(self):
"return the object the form will manipulate (load from & store to)"
annotations = IAnnotations(self.context)
return annotations[SOME_ANNOTATIONS_KEY_HERE]
This is assuming that a PersistentDict
has been previously stored at annotations[SOME_ANNOTATIONS_KEY_HERE]
- otherwise the above code will result in KeyError
. It would probably be a good idea to change above getContent
so that if the annotation does not yet exist, it is created and initialized with some default values.
Finally, note that for some reason, z3c.form
warns against enabling DictionaryField
for every mapping type, so it may be prudent to for example subclass PersistentDict
for form storage, rather than use it directly. I submitted an issue to z3c.form asking for clarification of that warning.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.