I created a content type with a RelationList field with a SelectFieldWidget. This content type is inside a Dexterity folder type (which I also created). The code of the content type for the RelationList field:
speaker = RelationList(
title=_(safe_unicode('Presenter')),
default=[],
value_type=RelationChoice(vocabulary='ConferenceSpeaker'),
required=False,
missing_value=[],
)
directives.widget(
'speaker',
SelectFieldWidget,
)
I use a vocabulary for this field (named utility in configure.zcml):
<utility
name="ConferenceSpeaker"
component=".vocabularies.ConferenceSpeakerVocabularyFactory" />
The code of the vocabulary:
@implementer(IVocabularyFactory)
class ConferenceSpeakerVocabulary(object):
def __call__(self, context=None):
terms = []
for brain in api.content.find(portal_type='collective.conferences.conferencespeaker', sort_on='sortable_title'):
terms.append(SimpleTerm(
value=brain.getObject(),
token=brain.UID,
title=safe_unicode('{0} ({1})').format(brain.Title, brain.getPath()),
))
return SimpleVocabulary(terms)
ConferenceSpeakerVocabularyFactory = ConferenceSpeakerVocabulary()
And the code of the conferencespeaker module:
# -*- coding: utf-8 -*-
from collective.conferences import _
from collective.conferences.common import allowedconferenceimageextensions
from collective.conferences.common import validateEmail
from collective.conferences.common import validateimagefileextension
from collective.conferences.common import validatePhoneNumber
from plone import api
from plone.app.textfield import RichText
from plone.autoform import directives
from plone.namedfile.field import NamedBlobImage
from plone.supermodel import model
from Products.CMFPlone.utils import safe_unicode
from Products.Five import BrowserView
from zope import schema
class IConferenceSpeaker(model.Schema):
lastname = schema.TextLine(
title=_(safe_unicode('Last name')),
required=True,
)
firstname = schema.TextLine(
title=_(safe_unicode('First name')),
required=True,
)
street = schema.TextLine(
title=_(safe_unicode('Street')),
description=_(safe_unicode(
'For those requiring visa, please add your full postal address details')),
required=False,
)
city = schema.TextLine(
title=_(safe_unicode('City')),
description=_(safe_unicode(
'For those requiring visa, please add your full postal address details')),
required=False,
)
postalcode = schema.TextLine(
title=_(safe_unicode('Postal Code')),
description=_(safe_unicode(
'For those requiring visa, please add your full postal address details')),
required=False,
)
country = schema.TextLine(
title=_(safe_unicode('Country')),
description=_(safe_unicode(
'For those requiring visa, please add your full postal address details')),
required=False,
)
email = schema.ASCIILine(
title=_(safe_unicode('Your email address')),
constraint=validateEmail,
required=True,
)
telephonenumber = schema.TextLine(
title=_(safe_unicode('Telephone Number')),
description=_(safe_unicode(
'Please fill in your telephone number so that we could get in contact with you by phone if necessary.')),
constraint=validatePhoneNumber,
required=False,
)
mobiletelepone = schema.TextLine(
title=_(safe_unicode('Mobile Telephone Number')),
description=_(safe_unicode(
'Please fill in your mobile telephone number so that we could get in contact with you '
'during the conference.')),
constraint=validatePhoneNumber,
required=True,
)
organisation = schema.TextLine(
title=_(safe_unicode('Organisation')),
required=False,
)
description = schema.Text(
title=_(safe_unicode('A short bio')),
required=True,
)
bio = RichText(
title=_(safe_unicode('Bio')),
required=False,
)
directives.mode(speakerpicture='display')
speakerpicture = schema.TextLine(
title=_(safe_unicode(
'The following file extensions are allowed for the picture '
'files (upper case and lower case and mix of both):')),
defaultFactory=allowedconferenceimageextensions,
)
picture = NamedBlobImage(
title=_(safe_unicode('Picture')),
description=_(safe_unicode('Please upload an image')),
constraint=validateimagefileextension,
required=False,
)
def notifyUser(self, event):
user = api.user.get_current()
sender = api.portal.get_registry_record(
'plone.email_from_address')
email = user.getProperty('email')
if not sender:
return
subject = 'Is this you?'
message = 'A speaker / leader of a workshop called {0} was added here {1}. If ' \
'this is you, everything is fine.'.format(self.title, self.absolute_url())
api.portal.send_email(
recipient='{0}'.format(email),
sender='{0}'.format(sender),
subject='{0}'.format(subject),
body='{0}'.format(message))
class ConferenceSpeakerView(BrowserView):
def talks_of_speaker(self):
catalog = api.portal.get_tool(name='portal_catalog')
# execute a search
results = catalog(speakertalk='Talk 1')
# examine the results
for brain in results:
url = brain.getURL()
return url
def talks_of_speaker2(self):
catalog = api.portal.get_tool(name='portal_catalog')
# execute a search
results = catalog(portal_type='collective.conferences.talk',
review_state='published')
# examine the results
for brain in results:
title = brain.Title
return title
def speakertalks(self):
speakername = self.context.title
results = api.content.find(portal_type='collective.conferences.talk',
review_state='published',
presenters=speakername)
objects = []
for brain in results:
objects.append(brain)
return objects
def speakerworkshops(self):
speakername = self.context.title
results = api.content.find(portal_type='collective.conferences.workshop',
review_state='published',
workshopleader=speakername)
objects = []
i
for brain in results:
objects.append(brain)
If I call the folder_contents view for the parent of my content objects, Plone is trying to find the contents of the folder but it never shows some results although it is showing that it is busy. I got the following traceback:
2020-08-05 10:39:42,463 ERROR [Zope.SiteErrorLog:251][waitress] 1596616782.46239830.6521426565906934 http://localhost:8080/Plone/@@getVocabulary
Traceback (innermost last):
Module ZPublisher.WSGIPublisher, line 156, in transaction_pubevents
Module ZPublisher.WSGIPublisher, line 338, in publish_module
Module ZPublisher.WSGIPublisher, line 256, in publish
Module ZPublisher.mapply, line 85, in mapply
Module ZPublisher.WSGIPublisher, line 62, in call_object
Module plone.app.content.browser.vocabulary, line 266, in __call__
Module plone.app.content.utils, line 24, in json_dumps
Module simplejson, line 412, in dumps
Module simplejson.encoder, line 296, in encode
Module simplejson.encoder, line 378, in iterencode
ValueError: Circular reference detected
2020-08-05 10:39:42,566 ERROR [Zope.SiteErrorLog:251][waitress] 1596616782.56519940.1180242857521221 http://localhost:8080/Plone/@@getVocabulary
Traceback (innermost last):
Module ZPublisher.WSGIPublisher, line 156, in transaction_pubevents
Module ZPublisher.WSGIPublisher, line 338, in publish_module
Module ZPublisher.WSGIPublisher, line 256, in publish
Module ZPublisher.mapply, line 85, in mapply
Module ZPublisher.WSGIPublisher, line 62, in call_object
Module plone.app.content.browser.vocabulary, line 266, in __call__
Module plone.app.content.utils, line 24, in json_dumps
Module simplejson, line 412, in dumps
Module simplejson.encoder, line 296, in encode
Module simplejson.encoder, line 378, in iterencode
ValueError: Circular reference detected
The issue seemed only appear with the RelationLIst - SelectFieldWidget combination. I got no such issue with the combination of a RelationList fields with a RadioFieldWidget. But in the case of my content type I need the option to select not only one relation.
Thanks for any hints for a solution.
Andreas