Realizing an optgroup-Tag based selection in Plone, by using TreeVocabularies

Optgroup tags in selections are a good way of grouping items of a selection list. In Plone you can archive this by using a TreeVocabulary with a SelectionWidget.

What we want to archive is something like this:

Subdivision selection items grouped by Country.

In a Dexterity content type, you could do the following:

from plone.app.z3cform.widget import SelectFieldWidget
from plone.autoform import directives
from plone.dexterity.content import Item
from plone.supermodel import model
from pprint import pprint
from zope import schema
from zope.interface import implementer
from zope.schema.vocabulary import TreeVocabulary

import pycountry


def available_things_factory():
    terms = {}
    for country in pycountry.countries:
        subdivs = pycountry.subdivisions.get(country_code=country.alpha_2)
        terms[(country.alpha_2, country.name)] = {}
        for subdiv in subdivs:
            terms[(country.alpha_2, country.name)][(subdiv.code, subdiv.code, f"{subdiv.name}")] = {}
    pprint(terms)
    return TreeVocabulary.fromDict(terms)


class ITodoTask(model.Schema):
    """Marker interface and Dexterity Python Schema for TodoTask"""

    directives.widget(country=SelectFieldWidget)
    country = schema.Choice(
        required=True,
        title=u"Country",
        vocabulary=available_things_factory(),
    )


@implementer(ITodoTask)
class TodoTask(Item):
    """Content-type class for ITodoTask"""

Here we are using the pycountry module to get some example data we can nest. We are iterating over all Countries and nest the Subdivision of each Country in it.

By @MrTango in
Tags :