Terms are used to provide choices for sequence widgets or any other construct needing them. Since Zope 3 already has sources and vocabularies, the base terms class simply builds on them.
Thus, let’s create a vocabulary first:
>>> from zope.schema import vocabulary
>>> ratings = vocabulary.SimpleVocabulary([
... vocabulary.SimpleVocabulary.createTerm(0, '0', u'bad'),
... vocabulary.SimpleVocabulary.createTerm(1, '1', u'okay'),
... vocabulary.SimpleVocabulary.createTerm(2, '2', u'good')
... ])
Now we can create the terms object:
>>> from z3c.form import term
>>> terms = term.Terms()
>>> terms.terms = ratings
Getting a term from a given value is simple:
>>> terms.getTerm(0).title
u'bad'
>>> terms.getTerm(3)
Traceback (most recent call last):
...
LookupError: 3
When converting values from their Web representation back to the internal representation, we have to be able to look up a term by its token:
>>> terms.getTermByToken('0').title
u'bad'
>>> terms.getTerm('3')
Traceback (most recent call last):
...
LookupError: 3
However, often we just want the value so asking for the value that is represented by a token saves usually one line of code:
>>> terms.getValue('0')
0
>>> terms.getValue('3')
Traceback (most recent call last):
...
LookupError: 3
You can also iterate through all terms:
>>> [entry.title for entry in terms]
[u'bad', u'okay', u'good']
Or ask how many terms you have in the first place:
>>> len(terms)
3
Finally the API allows you to check whether a particular value is available in the terms:
>>> 0 in terms
True
>>> 3 in terms
False
Now, there are several terms implementations that were designed for particular fields. Within the framework, terms are used as adapters with the follwoing discriminators: context, request, form, field, vocabulary/source and widget.
The first terms implementation is for Choice fields. Choice fields unfortunately can have a vocabulary and a source which behave differently. Let’s have a look a the vocabulary first:
>>> import zope.component >>> zope.component.provideAdapter(term.ChoiceTermsVocabulary) >>> import z3c.form.testing >>> request = z3c.form.testing.TestRequest() >>> import z3c.form.widget >>> widget = z3c.form.widget.Widget(request)>>> import zope.schema>>> ratingField = zope.schema.Choice( ... title=u'Rating', ... vocabulary=ratings)>>> terms = term.ChoiceTerms( ... None, request, None, ratingField, widget) >>> [entry.title for entry in terms] [u'bad', u'okay', u'good']
Sometimes choice fields only specify a vocabulary name and the actual vocabulary is looked up at run time.
>>> ratingField2 = zope.schema.Choice(
... title=u'Rating',
... vocabulary='Ratings')
Initially we get an error because the “Ratings” vocabulary is not defined:
>>> terms = term.ChoiceTerms(
... None, request, None, ratingField2, widget)
Traceback (most recent call last):
...
VocabularyRegistryError: unknown vocabulary: 'Ratings'
Let’s now register the vocabulary under this name:
>>> def RatingsVocabulary(obj): ... return ratings>>> from zope.schema import vocabulary >>> vr = vocabulary.getVocabularyRegistry() >>> vr.register('Ratings', RatingsVocabulary)
We should now be able to get all terms as before:
>>> terms = term.ChoiceTerms(
... None, request, None, ratingField, widget)
>>> [entry.title for entry in terms]
[u'bad', u'okay', u'good']
A similar terms implementation exists for a Bool field:
>>> truthField = zope.schema.Bool()>>> terms = term.BoolTerms(None, None, None, truthField, None) >>> [entry.title for entry in terms] [u'yes', u'no']
In case you don’t like the choice of ‘yes’ and ‘no’ for the labels, we can subclass the BoolTerms class to control the display labels.
>>> class MyBoolTerms(term.BoolTerms): ... trueLabel = u'True' ... falseLabel = u'False'>>> terms = MyBoolTerms(None, None, None, truthField, None) >>> [entry.title for entry in terms] [u'True', u'False']
Finally, there are a terms adapters for all collections. But we have to register some adapters before using it:
>>> from z3c.form import term >>> zope.component.provideAdapter(term.CollectionTerms) >>> zope.component.provideAdapter(term.CollectionTermsVocabulary) >>> zope.component.provideAdapter(term.CollectionTermsSource)>>> ratingsField = zope.schema.List( ... title=u'Ratings', ... value_type=ratingField)>>> terms = term.CollectionTerms( ... None, request, None, ratingsField, widget) >>> [entry.title for entry in terms] [u'bad', u'okay', u'good']
Basic sources need no context to compute their value. Let’s create a source first:
>>> from zc.sourcefactory.basic import BasicSourceFactory
>>> class RatingSourceFactory(BasicSourceFactory):
... _mapping = {10: u'ugly', 20: u'nice', 30: u'great'}
... def getValues(self):
... return self._mapping.keys()
... def getTitle(self, value):
... return self._mapping[value]
As we did not include the configure.zcml of zc.sourcefactory we have to register some required adapters manually. We also need the ChoiceTermsSource adapter:
>>> import zope.component
>>> import zc.sourcefactory.browser.source
>>> import zc.sourcefactory.browser.token
>>> zope.component.provideAdapter(
... zc.sourcefactory.browser.source.FactoredTerms)
>>> zope.component.provideAdapter(
... zc.sourcefactory.browser.token.fromInteger)
>>> zope.component.provideAdapter(term.ChoiceTermsSource)
Sources can be used with Choice fields like vocabularies. First we create a field based on the source:
>>> sourceRatingField = zope.schema.Choice(
... title=u'Sourced Rating',
... source=RatingSourceFactory())
We connect the field to a widget to see the ITerms adapter for sources at work:
>>> terms = term.ChoiceTerms(
... None, request, None, sourceRatingField, widget)
Iterating over the terms adapter returnes the term objects:
>>> [entry for entry in terms]
[<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>]
>>> len(terms)
3
>>> [entry.token for entry in terms]
['10', '20', '30']
>>> [entry.title for entry in terms]
[u'ugly', u'nice', u'great']
Using a token it is possible to look up the term and the value:
>>> terms.getTermByToken('20').title
u'nice'
>>> terms.getValue('30')
30
With can test if a value is in the source:
>>> 30 in terms
True
>>> 25 in terms
False
Finally, there are terms adapters for all collections:
>>> sourceRatingsField = zope.schema.List( ... title=u'Sourced Ratings', ... value_type=sourceRatingField)>>> terms = term.CollectionTerms( ... None, request, None, sourceRatingsField, widget) >>> [entry.title for entry in terms] [u'ugly', u'nice', u'great']
Contextual sources depend on the context they are called on. Let’s create a context and a contextual source:
>>> from zc.sourcefactory.contextual import BasicContextualSourceFactory
>>> class RatingContext(object):
... base_value = 10
>>> class ContextualRatingSourceFactory(BasicContextualSourceFactory):
... _mapping = {10: u'ugly', 20: u'nice', 30: u'great'}
... def getValues(self, context):
... return [context.base_value + x for x in self._mapping.keys()]
... def getTitle(self, context, value):
... return self._mapping[value - context.base_value]
As we did not include the configure.zcml of zc.sourcefactory we have to register some required adapters manually. We also need the ChoiceTermsSource adapter:
>>> import zope.component
>>> import zc.sourcefactory.browser.source
>>> import zc.sourcefactory.browser.token
>>> zope.component.provideAdapter(
... zc.sourcefactory.browser.source.FactoredContextualTerms)
>>> zope.component.provideAdapter(
... zc.sourcefactory.browser.token.fromInteger)
>>> zope.component.provideAdapter(term.ChoiceTermsSource)
Contextual sources can be used with Choice fields like vocabularies. First we create a field based on the source:
>>> contextualSourceRatingField = zope.schema.Choice(
... title=u'Context Sourced Rating',
... source=ContextualRatingSourceFactory())
We create an context object and connect the field to a widget to see the ITerms adapter for sources at work:
>>> rating_context = RatingContext()
>>> rating_context.base_value = 100
>>> terms = term.ChoiceTerms(
... rating_context, request, None, contextualSourceRatingField, widget)
Iterating over the terms adapter returnes the term objects:
>>> [entry for entry in terms]
[<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>]
>>> len(terms)
3
>>> [entry.token for entry in terms]
['110', '120', '130']
>>> [entry.title for entry in terms]
[u'ugly', u'nice', u'great']
Using a token, it is possible to look up the term and the value:
>>> terms.getTermByToken('120').title
u'nice'
>>> terms.getValue('130')
130
With can test if a value is in the source:
>>> 130 in terms
True
>>> 125 in terms
False
Finally, there are terms adapters for all collections:
>>> contextualSourceRatingsField = zope.schema.List( ... title=u'Contextual Sourced Ratings', ... value_type=contextualSourceRatingField)>>> terms = term.CollectionTerms( ... rating_context, request, None, contextualSourceRatingsField, widget) >>> [entry.title for entry in terms] [u'ugly', u'nice', u'great']