The following code shows two custom FieldSerializer adapters which handle the values of Choice and MultiChoice (Collection) fields. For doing this, we register one adapter for the IChoice interface and one adapter for ICollection interface. Both also support vocabularies provided by collective.taxonomy.
By default the Plone REST API would give us just the plain tokens back, because that's what is actually stored when you use a Selection or Multiselection field. But on the client side we want the token and also the title, so that we can easily show it. Therefor we want something like this as the value for a Choice field.
Expected response
IChoice field
"solution\_category": {
"title": "A nice title",
"token": "a-nice-title"
},
ICollection field
"solution\_category": [
{
"title": "A nice title",
"token": "a-nice-title"
},
{
"title": "An awesome title",
"token": "an-awesome-title"
},
]
Implementation
restapi.py
from plone.dexterity.interfaces import IDexterityContent
from plone.restapi.interfaces import IFieldSerializer
from plone.restapi.serializer.converters import json\_compatible
from zope.component import adapter
from zope.component import getUtility
from zope.interface import implementer
from zope.interface import Interface
from zope.schema.interfaces import IChoice
from zope.schema.interfaces import ICollection
from zope.schema.interfaces import IVocabularyFactory
def \_get\_vocab\_term(context, field, value):
""" Get vocab term dict
returns: {'token': token, 'title': title}
"""
vocab\_term = {
'token': None,
'title': None,
}
vocab\_term['token'] = value
factory = getUtility(IVocabularyFactory, field)
if not factory:
return vocab\_term
# collective.taxonomy support:
if hasattr(factory, 'translate'):
vocab\_term['title'] = \_get\_taxonomy\_vocab\_title(
context,
factory,
value,
)
elif IVocabularyFactory.providedBy(factory):
vocab\_term['title'] = \_get\_vocab\_title(
context,
factory,
value,
)
return vocab\_term
def \_get\_taxonomy\_vocab\_title(context, factory, value):
vocab\_title = factory.translate(
value,
context=context,
)
return vocab\_title
def \_get\_vocab\_title(context, factory, value):
vocab = factory(context)
vocab\_title = vocab.getTermByToken(value).title
return vocab\_title
class BaseFieldSerializer(object):
def \_\_init\_\_(self, field, context, request):
self.context = context
self.request = request
self.field = field
def \_\_call\_\_(self):
return json\_compatible(self.get\_value())
@adapter(IChoice, IDexterityContent, Interface)
@implementer(IFieldSerializer)
class ChoiceFieldSerializer(BaseFieldSerializer):
"""
"""
def get\_value(self, default=None):
value = getattr(
self.field.interface(self.context),
self.field.\_\_name\_\_,
default,
)
if not value:
return
term = \_get\_vocab\_term(
self.context,
self.field.vocabularyName,
value,
)
return term
@adapter(ICollection, IDexterityContent, Interface)
@implementer(IFieldSerializer)
class CollectionFieldSerializer(BaseFieldSerializer):
"""
"""
def get\_value(self, default=None):
terms = []
values = getattr(
self.field.interface(self.context),
self.field.\_\_name\_\_,
default,
)
if not values:
return
if not IChoice.providedBy(self.field.value\_type):
return
for value in values:
term = \_get\_vocab\_term(
self.context,
self.field.value\_type.vocabularyName,
value,
)
terms.append(term)
return terms
Registration
To activate this, we need to register the two adapters:
configure.zcml
<adapter factory=".restapi.ChoiceFieldSerializer" />
<adapter factory=".restapi.CollectionFieldSerializer" />
Top comments (0)