Plone 5/Relation/AjaxSelectFieldWidget - How can I get AjaxSelectFieldWidget to work with relations?

I'm trying to follow an example using AjaxSelectWidget with RelationChoice on the plone training site (43. Relations – Mastering Plone 6 Development — Plone Training 2022 documentation) and I'm getting an error where I think it can't retrieve a vocabulary.

I tried their example, which queries Document and Event types, in my interface.

from plone.supermodel import model 
from z3c.relationfield.schema import RelationChoice, RelationList
from plone.app.vocabularies.catalog import StaticCatalogVocabulary
from plone.app.z3cform.widget import AjaxSelectFieldWidget

class IMyType(model.Schema):

    relationlist_field_ajax_select = RelationList(
        title='Relationlist Field with AJAXSelect',
        description='z3c.relationfield.schema.RelationList',
        value_type=RelationChoice(
            vocabulary=StaticCatalogVocabulary(
                {
                    'portal_type': ['Document', 'Event'],
                    'review_state': 'published',
                }
            )
        ),
        required=False,
    )
    directives.widget(
        'relationlist_field_ajax_select',
        AjaxSelectFieldWidget,
            vocabulary=StaticCatalogVocabulary(
                {
                'portal_type': ['Document', 'Event', 'Folder'],
                },
                title_template='{brain.Type}: {brain.Title} at {path}',
            ),
        pattern_options={  # Options for Select2
            'minimumInputLength': 2,
            'ajax': {'quietMillis': 500},
    },
)

I get an error:

2022-02-24 08:38:53,751 ERROR   [Zope.SiteErrorLog:252][waitress-0] 1645709933.74932720.4615189842801354 http://localhost:8080/Plone/stff/++add++My%20Type
Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 162, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 371, in publish_module
  Module ZPublisher.WSGIPublisher, line 266, in publish
  Module ZPublisher.mapply, line 85, in mapply
  Module ZPublisher.WSGIPublisher, line 63, in call_object
  Module plone.z3cform.layout, line 63, in __call__
  Module plone.z3cform.layout, line 57, in update
  Module z3c.form.form, line 281, in render
  Module z3c.form.form, line 162, in render
  Module zope.browserpage.viewpagetemplatefile, line 46, in __call__
  Module zope.pagetemplate.pagetemplate, line 133, in pt_render
  Module Products.PageTemplates.engine, line 378, in __call__
  Module z3c.pt.pagetemplate, line 176, in render
  Module chameleon.zpt.template, line 302, in render
  Module chameleon.template, line 192, in render
  Module 824ede03b81b25c3bf0a8ae074dc4cc9, line 115, in render
  Module 4cc2a64e3acfc7371c6e0822181f9805, line 921, in render_titlelessform
  Module 4cc2a64e3acfc7371c6e0822181f9805, line 1227, in render_fields
  Module 4cc2a64e3acfc7371c6e0822181f9805, line 1764, in render_widget_rendering
  Module 4cc2a64e3acfc7371c6e0822181f9805, line 1871, in render_field
  Module zope.tales.expressions, line 250, in __call__
  Module Products.PageTemplates.Expressions, line 196, in _eval
  Module Products.PageTemplates.Expressions, line 126, in render
  Module zope.browserpage.simpleviewclass, line 41, in __call__
  Module zope.browserpage.viewpagetemplatefile, line 81, in __call__
  Module zope.browserpage.viewpagetemplatefile, line 46, in __call__
  Module zope.pagetemplate.pagetemplate, line 133, in pt_render
  Module Products.PageTemplates.engine, line 378, in __call__
  Module z3c.pt.pagetemplate, line 176, in render
  Module chameleon.zpt.template, line 302, in render
  Module chameleon.template, line 214, in render
  Module chameleon.utils, line 53, in raise_with_traceback
  Module chameleon.template, line 192, in render
  Module 2aed304def3b7a89fba60d1ce9384bea, line 991, in render
  Module 2aed304def3b7a89fba60d1ce9384bea, line 502, in render_widget_wrapper
  Module zope.tales.expressions, line 250, in __call__
  Module Products.PageTemplates.Expressions, line 196, in _eval
  Module Products.PageTemplates.Expressions, line 126, in render
  Module plone.app.z3cform.widget, line 117, in render
  Module plone.app.z3cform.widget, line 479, in _base_args
  Module plone.app.z3cform.widget, line 431, in _ajaxselect_options
  Module plone.app.z3cform.widget, line 395, in get_vocabulary
  Module zope.component._api, line 169, in queryUtility
  Module zope.interface.registry, line 287, in queryUtility
ValueError: name is not a string or unicode

 - Expression: "widget/render"
 - Filename:   ... /browser/overrides/plone.app.z3cform.templates.widget.pt
 - Location:   (line 40: col 54)
- Source:     ... xt" tal:replace="structure widget/render"
                                          ^^^^^^^^^^^^^
 - Expression: "widget/@@ploneform-render-widget"
 - Filename:   ... rm-3.2.2-py3.8.egg/plone/app/z3cform/templates/macros.pt
 - Location:   (line 99: col 81)
 - Source:     ... place="structure widget/@@ploneform-render-widget"/>
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "context/@@ploneform-macros/titlelessform"
 - Filename:   ... 1.3-py3.8.egg/plone/z3cform/pagetemplates/wrappedform.pt
 - Location:   (line 1: col 22)
 - Source:     ... e use-macro="context/@@ploneform-macros/titlelessform" />
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Arguments:  template: <zope.browserpage.viewpagetemplatefile.ViewPageTemplateFile object at 0x7f61b3c4fbe0>
           options: {}
           args: ()
           nothing: None
           modules: <zope.pagetemplate.engine.TraversableModuleImporter object at 0x7f61bf2e2a30>
           request: <WSGIRequest, URL=http://localhost:8080/Plone/stff/++add++My%20Type>
           view: <Products.Five.browser.metaconfigure.RenderWidget object at 0x7f61b3c4fca0>
           context: <AjaxSelectWidget 'form.widgets.relationlist_field_ajax_select'>
           views: <zope.browserpage.viewpagetemplatefile.ViewMapper object at 0x7f61b3c4fb20>
           default: <DEFAULT>
           repeat: <Products.PageTemplates.engine.RepeatDictWrapper object at 0x7f61ba8445c0>
           loop: {}
           target_language: None
           translate: <function BaseTemplate.render.<locals>.translate at 0x7f61b419fe50>

I walked backwards through the traceback.
In plone.app.z3cform/widget.py, on line 395, it tries to get the vcoabulary:

    def get_vocabulary(self):
        if self.vocabulary:
            factory = queryUtility(
                IVocabularyFactory,
                self.vocabulary,
            )
            if factory:
                return factory(self._view_context())

Its passing the vocabulary for the 'name' parameter of queryUtility, which expects a string or unicode.

So if possible, I would like to know what I'm doing wrong or is this example incorrect? I tried replacing vocabulary with source in the interface in case that was the issue, but I was getting an error where its trying to go into PrincipleUsers (term?) for some reason.

2022-02-24 09:36:22,179 ERROR   [Zope.SiteErrorLog:252][waitress-2] 1645713382.17900180.8887186255940857 http://localhost:8080/Plone/stff/++add++My%20Type/++widget++form.widgets.relationlist_field_ajax_select
Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 162, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 371, in publish_module
  Module ZPublisher.WSGIPublisher, line 250, in publish
  Module ZPublisher.BaseRequest, line 518, in traverse
  Module ZPublisher.BaseRequest, line 329, in traverseName
  Module zope.traversing.namespace, line 165, in namespaceLookup
  Module plone.z3cform.traversal, line 54, in traverse
  Module plone.dexterity.browser.add, line 141, in update
  Module plone.z3cform.fieldsets.extensible, line 65, in update
  Module plone.z3cform.patch, line 30, in GroupForm_update
  Module z3c.form.group, line 141, in update
  Module z3c.form.group, line 52, in update
  Module z3c.form.group, line 48, in updateWidgets
  Module z3c.form.field, line 277, in update
  Module plone.app.z3cform.widget, line 444, in update
  Module z3c.form.browser.text, line 36, in update
  Module z3c.form.browser.widget, line 171, in update
  Module Products.CMFPlone.patches.z3c_form, line 47, in _wrapped
  Module z3c.form.widget, line 132, in update
  Module plone.app.z3cform.converters, line 181, in toWidgetValue
  Module plone.app.vocabularies.principals, line 166, in getTerm
  Module plone.app.vocabularies.principals, line 131, in _get_term_from_source
ValueError: value or token must be provided (only one of those)


Also, I was getting the same issue if I just stuck to using the RelatedItemsFieldWidget and CatalogSource. This is different than an earlier question I asked, where a permission check in plone.app.content/browser/vocabulary.py was preventing results from being shown.

I have versions:

Plone = 5.2.4
plone.app.content = 3.8.7 *
plone.app.z3cform = 3.2.2
zope.component = 4.6.2
zope.interface = 5.2.0
plone.app.vocabularies = 4.3.0

*Modified plone.app.content/browser/vocabulary.py to bypass the permission issue by replacing the default permission 'cmf.ModifyPortalContent' with None

Edited: not sure if PrincipleUsers is the correct term.

This is an example of the Plone 6 training.
If you pin versions for plone.app.z3cform and plone.app.vocabularies like in https://dist.plone.org/release/6-latest/versions.cfg it should be fine.

I apologize, I guess I gave the wrong link. Although, when I click it, it takes me to what I thought was a Plone 5 training site.

If this is intended for Plone 6, Is there an example available for Plone 5 at all? We're not ready to move to Plone 6 just yet.

The example should work in Plone 5 as well, given you use the latest Plone 5.2 release. If not, come back and ask here.

It's the upcomming plone.app.z3cform version 4 that can handle a StaticCatalogVocabulary

1 Like

This example must be meant for Plone 6.
I was curious about the version 4 of plone.app.z3cform up there and its looking for iconresolver, which is used for Plone 6.

Apart from the training example: what do you want to have in your project?

I want to have a relation field that can make a relation between an instance of one content type (MyContentType) to one or more several other instances of another content type (AnotherContentType) on a field (ex. customer). However, there's potentially more than 50 instances of AnotherContentType. There's also other relation fields between MyContentType and other content types. We're trying to move to the relation catalog so we can reduce querying and have a more efficient means of keeping track of "references/links" between objects.

Currently, I'm using the SelectFieldWidget and a custom vocabulary that consists terms where the value is the object. This is an expensive approach because of the getObject call from a catalog query. So I want to use AjaxSelectFieldWidget to hopefully make it faster.

Edit: We don't like the default related items widget because of permission issues we've had.