Update DataGridField with RelationChoice column -> 'NO_VALUE' object has no attribute 'getPhysicalPath'

I have a working DataGridField which requires a new column more_link with a RelationChoice field:

class ICollectionRow(model.Schema):

    collection = schema.Choice(
        title=_("Collection"), source=get_collections, required=True
    )
    title = schema.TextLine(title=_("Title"), required=True)
    num_items = schema.Int(title=_("Number items"), default=5, required=True)
    more_link = RelationChoice(
        title=_("Link to 'more...'"),
        description=_("Reference to object for 'more...'"),
        vocabulary="plone.app.vocabularies.Catalog",
        default=None,
        required=False,
    )

This causes this error...anything missing here for the more_link definition?

  Module z3c.form.browser.widget, line 171, in update
  Module z3c.form.widget, line 496, in update
  Module Products.CMFPlone.patches.z3c_form, line 47, in _wrapped
  Module z3c.form.widget, line 132, in update
  Module z3c.form.widget, line 491, in value
  Module collective.z3cform.datagridfield.datagridfield, line 171, in updateWidgets
  Module z3c.form.widget, line 432, in updateWidgets
  Module collective.z3cform.datagridfield.datagridfield, line 149, in getWidget
  Module z3c.form.browser.widget, line 171, in update
  Module z3c.form.object, line 217, in update
  Module collective.z3cform.datagridfield.datagridfield, line 311, in updateWidgets
  Module z3c.form.object, line 208, in updateWidgets
  Module collective.z3cform.datagridfield.datagridfield, line 439, 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 132, in update
  Module collective.z3cform.datagridfield.datagridfield, line 446, in updateWidgets
  Module z3c.form.form, line 136, in updateWidgets
  Module z3c.form.field, line 277, in update
  Module plone.app.z3cform.widget, line 527, 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 112, in update
  Module zope.schema._field, line 507, in bind
  Module zope.schema._field, line 491, in _resolve_vocabulary
  Module Zope2.App.schema, line 32, in get
  Module plone.app.vocabularies.catalog, line 647, in __call__
AttributeError: 'NO_VALUE' object has no attribute 'getPhysicalPath'

Likely related to my own question to the same issue. However the solution discussed here does not work in the context of the submodel of the DataGridField

@zopyx I ran into similar issues recently where I wanted to add a related items path to a datagrid field row in a control panel. I got the Datagridfield part working, by re-implementing the CatalogVocabularyFactory and adding 3 extra line to 'fix' the context which gets lost:


@implementer(IVocabularyFactory)
class CatalogVocabularyFactory(object):
    def __call__(self, context, query=None):

        # Make sure we have a context if rendered inside a datagridfield Row
        if not IDexterityContent.providedBy(context):
            req = getRequest()
            context = req.PARENTS[0]  # pylint: disable=no-member

        parsed = {}
        if query:
            parsed = parseQueryString(context, query["criteria"])
            if "sort_on" in query:
                parsed["sort_on"] = query["sort_on"]
            if "sort_order" in query:
                parsed["sort_order"] = str(query["sort_order"])

        # If no path is specified check if we are in a sub-site and use that
        # as the path root for catalog searches
        if "path" not in parsed:
            site = getSite()
            nav_root = getNavigationRootObject(context, site)
            site_path = site.getPhysicalPath()
            if nav_root and nav_root.getPhysicalPath() != site_path:
                parsed["path"] = {
                    "query": "/".join(nav_root.getPhysicalPath()),
                    "depth": -1,
                }
        return CatalogVocabulary.fromItems(parsed, context)

If you base your related items widget in the datagridrow on this vocabulary, the 'NO_VALUE' error message should be gone.

Basically you need to 'patch' any vocabulary used in fields in the DataGridfield row schema to catch the missing context case.

rolling eyes :roll_eyes:

I am pretty sure I have done this without any 'patching'.

Taken from memory (dont have access to Plone at the moment):

Is something like this possible ?

value_type=RelationChoice(
        source=CatalogSource(portal_type=Something

Perhaps...at least my error goes away. However, I can not select any item through the widget.

This is all weird...I changed my code to

class ICollectionRow(model.Schema):

    collection = schema.Choice(
        title=_("Collection"), source=get_collections, required=True
    )
    title = schema.TextLine(title=_("Title"), required=True)
    num_items = schema.Int(title=_("Number items"), default=5, required=True)
    more_link = RelationChoice(
        title=_("Link to 'more...'"),
        description=_("Reference to object for 'more...'"),
        source=CatalogSource(portal_type=['Folder', 'richfolder']),
        default=None,
        required=False,
    )

and I can reference a Folder.

The result looks like this, however the the folder referenced through more_link has an empty URL!?

(Pdb) pp d
{'collection': '13c3f735189446f4aad539f3a5614bf4',
 'more_link': <Richfolder at fortbildung>,
 'num_items': 3,
 'title': 'Aktuelles'}
(Pdb) type(d['more_link'])
<class 'dynamore.policy.content.richfolder.Richfolder'>
(Pdb) pp d['more_link'].absolute_url()
''

Again: takten from memory, so untested, but I think I had to set the widget, too.

Maybe something like this:

directives.widget(
    'relatedItems',
    RelatedItemsFieldWidget,
    pattern_options={
        'basePath': '/',
        "mode": "auto",
        "favorites": []
        }
    )

Note: the basePath, mode and favourites have been discussed here earlier. I can not remember if 'auto' always worked

Also see Browsing for content in AjaxSelectWidget no longer possible? where the selectable_types parameter in the pattern_options is discussed.

Note: had the same issues here and fixed it with the new implementation of DictRowConverter which converts all columns to their correct schema field/widget value: fix dataconverters for DictRow by petschki · Pull Request #150 · collective/collective.z3cform.datagridfield · GitHub