GhitaB
GhitaB

Reputation: 3437

Optional field in schema interface

I have this user schema defined in a plone add-on to be used for multiple websites.

class IUser(Interface):
    userid = schema.TextLine(
        title=_("User id"),
        required=True,
        constraint=validate_userid,
    )

    email = schema.TextLine(
        title=_(u"Email"),
        required=True,
        constraint=validate_email
    )

    optional_type = schema.Choice(
        title=_(u"User type"),
        vocabulary="user_types",
        required=True,
    )

Sometimes the optional_type field is needed sometimes not. user_types is saved in portal_vocabularies. I want the field to be used only when the vocabulary exists and I want it to be ignored when the definition is missing.

I mean, I want this field to work for websites where it is used, but the user schema also to work in other case. For the moment I receive this error: ComponentLookupError: (<InterfaceClass zope.schema.interfaces.IVocabularyFactory>, 'user_types').

I know I can create an empty unused vocabulary, but do you have any better solution here?

Upvotes: 0

Views: 64

Answers (1)

GhitaB
GhitaB

Reputation: 3437

Not possible, but you can skip the error and make things look like the field doesn't exist. Good to know:

in fact user_types is not the name of a vocabulary but the name of a vocabulary factory (source)

So you can solve this without defining a vocabulary in portal_vocabularies. Just define a factory like:

foo.py:

from zope.interface import provider
from zope.schema.interfaces import IVocabularyFactory
from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary


@provider(IVocabularyFactory)
def user_types_vocabulary(context):
    items = [
        ('test1', u'Test value 1'),
        ('test2', u'Test value 2')
    ]

    terms = [
        SimpleTerm(value=pair[0], token=pair[0], title=pair[1])
        for pair in items
    ]
    return SimpleVocabulary(terms)

as utility:

configure.zcml:

  <utility name="user_types"
           component=".aaa.user_types_vocabulary" />

Then you can hide the field and just ignore it everywhere is not needed.

Upvotes: 1

Related Questions