zope.schema List - Save List of lists - plone

did i misunderstand something? I want to save a list of lists, or a set of lists....
I have this
fcurricula = schema.List(
title=_(u'Curricula'),
required=False)
I tried to save this:
[
[261, u'26-BEA', 138, 4, u'h\xf6ren, listen', 4.00, 0, u'655755sa939b9b10'],
[261, u'26-BEA', 138, 4, u'h\xf6ren, listen', 4.00, 0, u'655755sa939b9b10']
]
But I get following error
Module zope.tales.expressions, line 217, in __call__
Module Products.PageTemplates.Expressions, line 155, in _eval
Module Products.PageTemplates.Expressions, line 117, in render
Module dudal.db.browser.dbimport, line 216, in dudal_fcurricula_import
Module plone.registry.registry, line 47, in __setitem__
Module plone.registry.record, line 83, in _set_value
Module zope.schema._bootstrapfields, line 182, in validate
Module zope.schema._field, line 475, in _validate
Module zope.schema._bootstrapfields, line 309, in _validate
Module zope.schema._bootstrapfields, line 248, in _validate
Module zope.schema._bootstrapfields, line 233, in _validate
Module zope.schema._bootstrapfields, line 209, in _validate
WrongType: ([[261, u'26-BEA', 138, 4, u'h\xf6ren, listen', 4.0, 0, u'655755sa939b9b10'], [261, u'26-BEA', 138, 4, u'h\xf6ren, listen', 4.0, 0, u'655755sa939b9b10']], <type 'set'>, 'value')

You need to define the value_type of the list elements. In you case also a list--> nested list.
You may try something like this:
fcurricula = schema.List(
title=_(u'Curricula'),
required=False)
value_type=schema.List(...)
But I don't know if there is a widget for this use case.
From my point of view, the right widget for you ist a datagrid widget.
--> https://github.com/collective/collective.z3cform.datagridfield
It stores a list of dictionaries.
If you can properly name the columns in your nested list, you can use a List field with value_type="DictRow" with a datagridwidget.
Since you have to define a seperate schema you can also make sure, your list contains valid data.

Related

non required SelectFieldWidget

I have a dexterity content type and I'd like to have a Select-Field which is not required and which values came from a vocabulary.
This is the vocabulary:
#grok.provider(IContextSourceBinder)
def voc_test(context):
values = range(10, 21)
terms = map(lambda x: SimpleTerm(value=str(x),
title=str(x)), values)
return SimpleVocabulary(terms)
And this the definition of the field:
from plone.directives import dexterity, form
from plone.namedfile.field import NamedImage
from zope import schema
class IMyType(form.Schema):
...
form.widget('test', SelectFieldWidget)
test = schema.List(
title=_(u"Test"),
value_type=schema.Choice(source=vocabularies.voc_test),
description=_(u"desc_test"),
required=False,
)
What I get is a select field with my values from the vocabulary and the first value is 'No Value'. That is fine. But when I hit save and have 'No Value' selected a error message is shown:
Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module plone.z3cform.layout, line 66, in __call__
Module plone.z3cform.layout, line 50, in update
Module plone.dexterity.browser.edit, line 52, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 145, in update
Module plone.app.z3cform.csrf, line 21, in execute
Module z3c.form.action, line 98, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.dexterity.browser.edit, line 23, in handleApply
Module z3c.form.group, line 98, in extractData
Module z3c.form.form, line 147, in extractData
Module z3c.form.field, line 303, in extract
Module z3c.form.converter, line 316, in toFieldValue
Module z3c.form.term, line 41, in getValue
Module z3c.form.term, line 38, in getTermByToken
Module zope.schema.vocabulary, line 133, in getTermByToken
LookupError: --NOVALUE--
If I change:
required=False,
to
required=True
saving works.
Hopefully someone can help. Thanks.
Set a default that is within your vocabulary and make the field required so that "--NOVALUE--" is not in the options.
If, for some reason, you want to use "-- NOVALUE --" for that default, then add it to the vocabulary. If the field is set required, it will not be duplicated.

Vocabulary do not work on collective.z3cform.datagridfield's sub object schema because of the context is NO_VALUE

I'm working on a content type that uses datagridfield.
Within the subobject, I have a choice field with a custom vocabulary.
The vocabulary work outside the datagrid (If I use it directly in the content type's schema). But when I add it to the subobject, it doesn't work anymore.
Looking at the debug note, I see the vocabluary's context is NO_VALUE.
Any hint/direction to make this works ?
This is the simplest schema that won't work (I think):
# Import
from zope import schema
from zope.interface import Interface
from plone.directives import form
from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow
# The container
class IMenu(Interface):
dishes = schema.List(value_type=schema.TextLine())
# The vocabulary
#grok.provider(IContextSourceBinder)
def getDishes(context):
terms = [SimpleVocabulary.createTerm(dish, dish, dish) for dish in context.dishes]
return SimpleVocabulary(terms)
# The object line
class IOrderLine(Interface):
dish = schema.Choice(source=getDishes)
quantity = schema.Int()
# The object
class IOrder(Interface):
form.widget(dishes=DataGridFieldFactory)
dishes = schema.List(value_type=DictRow(schema=IOrderLine))
Now I register Menu, Order as dexterity content type, add a menu and tried to add an order within it, I got an error on Order add view and this is the traceback:
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module Products.PDBDebugMode.runcall, line 70, in pdb_runcall
Module ZPublisher.Publish, line 46, in call_object
Module plone.z3cform.layout, line 66, in __call__
Module plone.z3cform.layout, line 50, in update
Module plone.dexterity.browser.add, line 112, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 128, in update
Module z3c.form.form, line 134, in updateWidgets
Module z3c.form.field, line 277, in update
Module z3c.form.browser.multi, line 63, in update
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.widget, line 477, in update
Module collective.z3cform.datagridfield.datagridfield, line 107, in updateWidgets
Module collective.z3cform.datagridfield.datagridfield, line 91, in getWidget
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.object, line 217, in update
Module z3c.form.object, line 208, in updateWidgets
Module z3c.form.object, line 87, in update
Module plone.z3cform.patch, line 21, in BaseForm_update
Module z3c.form.form, line 150, in update
Module z3c.form.form, line 134, in updateWidgets
Module z3c.form.field, line 277, in update
Module z3c.form.browser.select, line 51, in update
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.widget, line 220, in update
Module z3c.form.widget, line 214, in updateTerms
Module zope.component._api, line 107, in getMultiAdapter
Module zope.component._api, line 120, in queryMultiAdapter
Module zope.component.registry, line 238, in queryMultiAdapter
Module zope.interface.adapter, line 532, in queryMultiAdapter
Module z3c.form.term, line 96, in ChoiceTerms
Module zope.schema._field, line 349, in bind
Module waga.game.core.content.interfaces, line 202, in getDishes
AttributeError: 'NO_VALUE' object has no attribute 'dishes'
> /home/quyetnd/Projects/waga.game.core/src/waga/game/core/content/interfaces.py(202)getDishes()
-> terms = [SimpleVocabulary.createTerm(dish, dish, dish) for dish in context.dishes]
The context object is an instance.
This is limitation in z3c.form (at least some versions, I think it has been fixed in the newer ones).
My ugly workaround in vocab source function:
if not context:
context = getSite()
if not context:
# Form is rendered from console without HTTP request traversing, etc.
# and thread local site variable is not set
raise RuntimeError("Oh snap. Beer time.")
...
http://developer.plone.org/serving/traversing.html#using-getsite

tile edit view wrong context for vocabularies

I have a persistent tile that has a choice field:
subjects = schema.List(
title=_(u"Subjects"),
value_type=schema.Choice(
vocabulary='my.subjects'
),
)
but this is failing on edit view rendering like this:
2013-05-22 18:37:56 ERROR Zope.SiteErrorLog 1369240676.330.546121806344 http://localhost:8082/plumi/##edit-tile/tagcloud.tile/home-cloud
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 46, in call_object
Module plone.z3cform.layout, line 70, in __call__
Module plone.z3cform.layout, line 54, in update
Module plone.app.tiles.browser.edit, line 48, in update
Module plone.app.tiles.browser.base, line 55, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 125, in update
Module plone.app.tiles.browser.base, line 71, in updateWidgets
Module z3c.form.field, line 275, in update
Module z3c.form.browser.orderedselect, line 50, in update
Module z3c.form.browser.widget, line 70, in update
Module z3c.form.widget, line 199, in update
Module z3c.form.widget, line 193, in updateTerms
Module zope.component._api, line 107, in getMultiAdapter
Module zope.component._api, line 120, in queryMultiAdapter
Module zope.component.registry, line 238, in queryMultiAdapter
Module zope.interface.adapter, line 532, in queryMultiAdapter
Module z3c.form.term, line 174, in CollectionTerms
Module zope.schema._field, line 352, in bind
Module Zope2.App.schema, line 33, in get
Module my.vocabularies, line 22, in __call__
Module Products.CMFCore.utils, line 10, in check_getToolByName
Module Products.CMFCore.utils, line 120, in getToolByName
AttributeError: portal_catalog
This happen because the context passed to the vocabulary call is the data dictionary of the tile. It happens also when using SearchableTextSourceBinder in another field:
source=SearchableTextSourceBinder(
{'is_folderish': True},
default_query='path:'
)
that makes plone.app.vocabularies.catalog fail:
Module plone.app.vocabularies.catalog, line 237, in __call__
Module plone.app.vocabularies.catalog, line 144, in __init__
Module Products.CMFCore.utils, line 10, in check_getToolByName
Module Products.CMFCore.utils, line 120, in getToolByName
AttributeError: portal_catalog
I don't know, if it's by design, but when a persistent tile is edited, context sensitive vocabulary will get its context (persistent tile data dictionary) without any acquisition wrapping. Therefore all lookups which rely on acquisition will fail.
You could try fixing your vocabulary to use portal root as its context for getToolByName-looksup using either plone.api.portal.get() or zope.component.hooks.getSite().
If you really need the current context, an ugly way would be to get zope.globalrequest.getRequest().get("PUBLISHED") which should be the current publishable context found by ZPublisher. It's usually a view, but you can get your context object from its acquisition chain. Of course, you should be very defensive with that approach.

ReferenceField causes AttributeError: 'function' object has no attribute '__of__' in a custom content type

I have created a custom content type that has a ReferenceField. When I set allowed_types to a default content type, such as Document or Folder, I do not get any problems upon saving or reindexing. However, when I set allowed_types to another custom content type, I get a very strange error. It appears I can set the UID in the ReferenceField fine and base_view does not break, but I cannot save or reindex the object.
Using:
Plone 4.0.1
Zope 2.12.11
Python 2.6.5 (r265:79063, Nov 21 2010, 11:58:21) [GCC 4.2.1 (Apple Inc. build 5664)]
Any ideas?
atapi.ReferenceField(
'issue_source',
storage=atapi.AnnotationStorage(),
widget=atapi.ReferenceWidget(
label=_(u"Issue Source"),
description=_(u"Please select the source document to which this issue corresponds."),
),
required=True,
relationship='issue_issue_source',
allowed_types=('Source Document'), # specify portal type names here ('Example Type',)
multiValued=False, #One to One relationship
),
In ipzope:
>>> issue
<Issue at /Plone/Members/test_user2/test-issue>
>>> issue.isReferenceable
1
>>> source_document
<SourceDocument at /Plone/test-folder/test-doc>
>>> issue.setIssue_source(source_document.UID())
>>> issue.getIssue_source()
<SourceDocument at /Plone/test-folder/test-doc>
>>> source_document
<SourceDocument at /Plone/test-folder/test-doc>
>>> issue.reindexObject()
> /Applications/Plone/plone-site/eggs/Products.CMFDynamicViewFTI-4.0-py2.6.egg/Products/CMFDynamicViewFTI/browserdefault.py(77)__call__()
76 context = aq_inner(self)
---> 77 template = template.__of__(context)
78 return template(context, context.REQUEST)
ipdb> quit
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "/Applications/Plone/plone-site/eggs/Products.Archetypes-1.6.3-py2.6.egg/Products/Archetypes/CatalogMultiplex.py", line 123, in reindexObject
c.catalog_object(self, url, idxs=lst)
File "/Applications/Plone/plone-site/eggs/Plone-4.0.1-py2.6.egg/Products/CMFPlone/CatalogTool.py", line 287, in catalog_object
update_metadata, pghandler=pghandler)
File "/Applications/Plone/plone-site/eggs/Products.PDBDebugMode-1.3.1-py2.6.egg/Products/PDBDebugMode/zcatalog.py", line 20, in catalog_object
update_metadata=update_metadata, pghandler=pghandler)
File "/Applications/Plone/plone-site/eggs/Zope2-2.12.11-py2.6-macosx-10.4-x86_64.egg/Products/ZCatalog/ZCatalog.py", line 529, in catalog_object
update_metadata=update_metadata)
File "/Applications/Plone/plone-site/eggs/Zope2-2.12.11-py2.6-macosx-10.4-x86_64.egg/Products/ZCatalog/Catalog.py", line 348, in catalogObject
self.updateMetadata(object, uid)
File "/Applications/Plone/plone-site/eggs/Zope2-2.12.11-py2.6-macosx-10.4-x86_64.egg/Products/ZCatalog/Catalog.py", line 278, in updateMetadata
newDataRecord = self.recordify(object)
File "/Applications/Plone/plone-site/eggs/Zope2-2.12.11-py2.6-macosx-10.4-x86_64.egg/Products/ZCatalog/Catalog.py", line 417, in recordify
if(attr is not MV and safe_callable(attr)): attr=attr()
File "/Applications/Plone/plone-site/eggs/Products.CMFDynamicViewFTI-4.0-py2.6.egg/Products/CMFDynamicViewFTI/browserdefault.py", line 77, in __call__
template = template.__of__(context)
AttributeError: 'function' object has no attribute '__of__'
When I click save through the web I get a slightly different error message:
2011-08-09 15:19:16 ERROR Zope.SiteErrorLog 1312895956.510.252592718824 http://127.0.0.1:8080/Plone/Members/test_user2/test-doc/atct_edit
Traceback (innermost last):
Module ZPublisher.Publish, line 127, in publish
Module ZPublisher.mapply, line 77, in mapply
Module Products.PDBDebugMode.runcall, line 70, in pdb_runcall
Module ZPublisher.Publish, line 47, in call_object
Module Products.CMFFormController.FSControllerPageTemplate, line 91, in __call__
Module Products.CMFFormController.BaseControllerPageTemplate, line 28, in _call
Module Products.CMFFormController.ControllerBase, line 231, in getNext
Module Products.CMFFormController.Actions.TraverseTo, line 38, in __call__
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 47, in call_object
Module Products.CMFFormController.FSControllerPythonScript, line 107, in __call__
Module Products.CMFFormController.ControllerBase, line 231, in getNext
Module Products.CMFFormController.Actions.TraverseTo, line 38, in __call__
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 47, in call_object
Module Products.CMFFormController.FSControllerPythonScript, line 105, in __call__
Module Products.CMFFormController.Script, line 145, in __call__
Module Products.CMFCore.FSPythonScript, line 130, in __call__
Module Shared.DC.Scripts.Bindings, line 324, in __call__
Module Shared.DC.Scripts.Bindings, line 361, in _bindAndExec
Module Products.PythonScripts.PythonScript, line 344, in _exec
Module script, line 1, in content_edit
- <FSControllerPythonScript at /Plone/content_edit used for /Plone/Members/test_user2/test-doc>
- Line 1
Module Products.CMFCore.FSPythonScript, line 130, in __call__
Module Shared.DC.Scripts.Bindings, line 324, in __call__
Module Shared.DC.Scripts.Bindings, line 361, in _bindAndExec
Module Products.PythonScripts.PythonScript, line 344, in _exec
Module script, line 13, in content_edit_impl
- <FSPythonScript at /Plone/content_edit_impl used for /Plone/Members/test_user2/test-doc>
- Line 13
Module Products.Archetypes.BaseObject, line 658, in processForm
Module Products.Archetypes.BaseObject, line 650, in _processForm
- __traceback_info__: (<Issue at /Plone/Members/test_user2/test-doc>, <Field nextPreviousEnabled(boolean:rw)>, <bound method Issue.setNextPreviousEnabled of <Issue at /Plone/Members/test_user2/test-doc>>)
Module Products.Archetypes.CatalogMultiplex, line 123, in reindexObject
Module Products.CMFPlone.CatalogTool, line 287, in catalog_object
Module Products.PDBDebugMode.zcatalog, line 20, in catalog_object
Module Products.ZCatalog.ZCatalog, line 529, in catalog_object
Module Products.ZCatalog.Catalog, line 348, in catalogObject
Module Products.ZCatalog.Catalog, line 278, in updateMetadata
Module Products.ZCatalog.Catalog, line 417, in recordify
Module Products.CMFDynamicViewFTI.browserdefault, line 77, in __call__
AttributeError: 'function' object has no attribute '__of__'
> /Applications/Plone/plone-site/eggs/Products.CMFDynamicViewFTI-4.0-py2.6.egg/Products/CMFDynamicViewFTI/browserdefault.py(77)__call__()
76 context = aq_inner(self)
---> 77 template = template.__of__(context)
78 return template(context, context.REQUEST)
This looks strange indeed, some tips:
Pass a tuple into allowed_types instead of string:
allowed_types=('Source Document', ),
Make sure you don't have a content item with an id that matches a catalog index id. Also make sure you don't index getIssue_source but if you need to, use getRawIssue_source. Reference fields return real content objects, so using the normal accessor would store the real content objects in the catalog. That will lead to a lot of surprises and problems later on. The raw accessor returns a uuid or a list of uuids, which you can use in a catalog query like:
query = {'UID': uids}
brains = catalog(query)

Vocabulary source, function is not iterable, with dexterity in Plone 4.1

I have a custom Dexterity content type with collective.z3c.datagridfield define in the following way:
class ILanguageRow(Interface):
# Interface that defines a datagrid row.
lang = schema.Choice(
title=_(u'Language'), required=True,
source=my_languages,
default=u'en',
)
(...)
This it the function that returns the vocabulary, as in http://plone.org/products/dexterity/documentation/manual/schema-driven-forms/customising-form-behaviour/vocabularies
#grok.provider(IContextSourceBinder)
def languages(context):
"""
Return a vocabulary of language codes and
translated language names.
"""
# z3c.form KSS inline validation hack
if not ISiteRoot.providedBy(context):
for item in getSite().aq_chain:
if ISiteRoot.providedBy(item):
context = item
# retrieve the localized language names.
request = getRequest()
portal_state = getMultiAdapter((context, request), name=u'plone_portal_state')
lang_items = portal_state.locale().displayNames.languages.items()
# build the dictionary
return SimpleVocabulary(
[SimpleTerm(value=lcode, token=lcode, title=lname)\
for lcode, lname in sorted(lang_items) if lcode in config.CV_LANGS]
)
Inside the Edit and Add Form, the Choice field works correctly. But when I attempt to save the content:
TypeError: argument of type 'function' is not iterable
2011-07-08 13:37:40 ERROR Zope.SiteErrorLog 1310125060.840.103138625259 http://localhost:8081/Plone/++add++my.content.types.curriculum
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 46, in call_object
Module plone.z3cform.layout, line 70, in __call__
Module plone.z3cform.layout, line 54, in update
Module my.content.types.curriculum, line 356, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 134, in update
Module z3c.form.group, line 47, in update
Module z3c.form.group, line 43, in updateWidgets
Module z3c.form.field, line 275, in update
Module z3c.form.browser.multi, line 61, in update
Module z3c.form.browser.widget, line 70, in update
Module z3c.form.widget, line 396, in update
Module z3c.form.widget, line 88, in update
Module z3c.form.widget, line 390, in set
Module collective.z3cform.datagridfield.datagridfield, line 112, in updateWidgets
Module collective.z3cform.datagridfield.datagridfield, line 90, in getWidget
Module z3c.form.browser.widget, line 70, in update
Module z3c.form.object, line 213, in update
Module z3c.form.widget, line 88, in update
Module collective.z3cform.datagridfield.datagridfield, line 216, in set
Module z3c.form.object, line 229, in applyValue
Module z3c.form.validator, line 67, in validate
Module zope.schema._bootstrapfields, line 153, in validate
Module zope.schema._field, line 325, in _validate
TypeError: argument of type 'function' is not iterable
Why is this happening?
This happens when the field hasn't been bound or is missing the context. Normally validation will happen against a "bound" field (bound = field.bind(context)) so that your context-aware vocabulary can be turned into a static vocabulary for this context. It'll still be a function (not called with the context) when this didn't take place.
I am not familiar enough with the datagrid widget setup to pinpoint where this goes wrong, but it appears that it generates widgets on-the-fly and I suspect it doesn't bind the fields for these correctly. Take a look at DataGridField.getWidget method of the collective.z3cform.datagridfield.datagridfield module and try to figure out what's going on there with a debugger and / or file a bug with the authors of the package.
I solved the problem by providing my custom vocabulary as a Named Vocabulary, in this way:
from Products.CMFCore.interfaces import ISiteRoot
from zope.component import getMultiAdapter
from zope.site.hooks import getSite
from zope.globalrequest import getRequest
from my.content import config
class LanguagesVocabulary(object):
grok.implements(IVocabularyFactory)
def __call__(self, context):
# z3c.form KSS inline validation hack
if not ISiteRoot.providedBy(context):
for item in getSite().aq_chain:
if ISiteRoot.providedBy(item):
context = item
# retrieve the localized language names.
request = getRequest()
portal_state = getMultiAdapter((context, request), name=u'plone_portal_state')
lang_items = portal_state.locale().displayNames.languages.items()
# build the dictionary
terms = [SimpleTerm(value=lcode, token=lcode, title=lname)\
for lcode, lname in sorted(lang_items) if lcode in config.CV_LANGS]
return SimpleVocabulary(terms)
grok.global_utility(LanguagesVocabulary, name=u"my.content.LanguagesVocabulary")
and in my Dexterity content type schemata:
class ILanguageRow(Interface):
# Interface that defines a datagrid row.
lang = schema.Choice(
title=_(u'Language'), required=True,
vocabulary=u"my.content.LanguagesVocabulary",
)
This way it works.

Resources