Standardwerte, Vokabularien und Autovervollständigung

Standardwerte

Oft vereinfacht es die Bedienung deutlich, wenn in Feldern Standardwerte eingetragen werden. Diese Werte werden im Hinzufügen-Formular gesetzt.

In unserem Beispiel sollen die Standardwerte für den Beginn und das Ende einer Veranstaltung eine Woche in der Zukunft liegen. Hierzu fügen wir in registration.py folgendes hinzu:

import datetime
...
@form.default_value(field=IRegistration['start'])
def startDefaultValue(data):
    # To get hold of the folder, do: context = data.context
    return datetime.datetime.today() + datetime.timedelta(7)

@form.default_value(field=IRegistration['end'])
def endDefaultValue(data):
    # To get hold of the folder, do: context = data.context
    return datetime.datetime.today() + datetime.timedelta(10)

Der Decorator kann ein oder mehrere Unterscheidungskriterien haben. Folgende Unterscheidungskriterien sind möglich:

context

Der Kontexttyp, z.B. ein Interface

request

Der Request-Tp, z.B. ein Layer Marker Interface

view

Der Formulartyp, z.B. eine Formularinstanz oder ein Interface.

field

Die Feld-Instanz oder das Interface eines Feldes

Neben dem default_value-Decorator gibt es noch zwei weitere Decorators:

widget

Der Widget-Typ, z.B. ein Interface

widget_label

bietet ein dynamische Label für Widgets wobei es dieselben Unterscheidungskriterien zulässt wie default_value.

button_label

bietet dynamische Label für Tasten mit den Unterscheidungskriterien content, ``request, form, manager und button.

In der Dokumentation zu plone.directives.form finden Sie weitere Informationen hierzu.

Vokabularien

Vokabularien werden üblicherweise zusammen mit Auswahlfeldern verwendet. Um nur eine Auswahl zuzulassen, kann das Choise-Feld direkt verwendet werden:

class IMySchema(form.Schema):
    myChoice = schema.Choice(...)

Für Multiple-Choice-Felder können List, Tuple, Set oder Frozenset mit value_type=schema.Choice verwendet werden, also z.B.:

class IMySchema(form.Schema):
    myList = schema.List(
        title=u"My list",
        value_type=schema.Choice(values=['red', 'green', 'blue', 'yellow']))

Ein Choice-Feld kann eines der folgenden Argumente erhalten:

  • Werte aus einer Liste statischer Werte

  • Werte aus einer Quelle, die mit IContextSourceBinder oder einer ISource-Intanz angegeben werden

  • Werte können aus einem Vokabular stammen, das als ÌVocabulary-Instanz oder als Name eines IVocabularyFactory-Utility angegeben wird

term

Eintrag in ein Vokabular

token

ASCII-Zeichenkette, die beim Abschicken eines Formulars übermittelt wird um den Term eindeutig zu identifizieren.

value

Der aktuelle Wert, der in einem Objekt gespeichert wird

title

Übersetzbare Unicode-Zeichenkette

Verfügbare Vokabularien

In Plone werden Ihnen bereits eine ganze Reihe von Vokabularien in plone.app.vocabularies zur Verfügung gestellt. Die gebräuchlichsten sind:

plone.app.vocabularies.AvailableContentLanguages

Eine Liste aller verfügbaren Sprachen

plone.app.vocabularies.SupportedContentLanguages

Eine Liste aller aktuell unterstützten Sprachen

plone.app.vocabularies.Roles

Die in der Site verfügbaren Rollen

plone.app.vocabularies.PortalTypes

Eine Liste der im Portal Types Tool registrierten Artikeltypen

plone.app.vocabularies.ReallyUserFriendlyTypes

Eine Liste derjenigen Artikeltypen, die für Nutzer von Bedeutung sind

plone.app.vocabularies.Workflows

Eine Liste aller Arbeitsabläufe

plone.app.vocabularies.WorkflowStates

Eine Liste aller Arbeitsablaufstadien

plone.app.vocabularies.WorkflowTransitions

Eine Liste aller Übergänge zwischen Arbeitsablaufstadien

Mit plone.principalsource steht uns ein weiteres Paket mit verschiedenen Vokabularien bereit, das zur Auswahl von Nutzern und Gruppen hilfreich ist:

plone.principalsource.Users

Eine Liste aller Nutzer

plone.principalsource.Groups

Eine Liste aller Gruppen

plone.principalsource.Principals

Eine Liste aller Berechtigungen für Nutzer und Gruppen

Statische Vokabularien

Hier ein Beispiel für ein statisches Vokabular:

from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm

organisers = SimpleVocabulary(
    [SimpleTerm(value=u'vsc', title=_(u'Veit Schiele Communications')),
     SimpleTerm(value=u'zopyx', title=_(u'Zopyx Limited'))]
    )

organiser = schema.Choice(
            title=_(u"Organiser"),
            vocabulary=organisers,
            required=False,
        )

Dynamische Vokabularien

Statische Vokabularien sind in zweierlei Hinsicht beschränkt: zum einen sind sie hartkodiert in Python, zum anderen werden die gespeicherten Werte nicht getrennt von den Labels gespeichert.

Ein dynamische Vokabular kann nun erzeugt werden indem ein sog. Context Source Binder verwendet wird. Ein solcher kann einfach aufgerufen werden durch eine Funktion oder ein Objekt mit einer __call__-Methode, die das IContextSourceBinder-Interface zusammen mit einem Kontext-Argument bereitstellt. Der Aufruf soll ein Vokabular ausgeben, das am einfachsten zu bekommen ist, wenn die SimpleVocabulary-Klasse aus zope.schema verwendet wird.

Im folgenden nun ein Beispiel für eine Funktion, die alle Nutzer einer bestimmten Gruppe zurückgibt:

from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary
from Products.CMFCore.utils import getToolByName

@grok.provider(IContextSourceBinder)
def possibleOrganisers(context):
    acl_users = getToolByName(context, 'acl_users')
    group = acl_users.getGroupById('organisers')
    terms = []

    if group is not None:
        for member_id in group.getMemberIds():
            user = acl_users.getUserById(member_id)
            if user is not None:
                member_name = user.getProperty('fullname') or member_id
                terms.append(SimpleVocabulary.createTerm(member_id, str(member_id), member_name))

   return SimpleVocabulary(terms)

Parametriesierte Vokabularien

Das obige Beispiel kann erweitert werden indem der Gruppenname aus der Funktion herausgenommen wird und sich dann für jedes Feld unabhängig setzen lässt. Hierfür wird dann IContextSourceBinder in eine eigene Klasse ausgelagert, die mit dem Gruppennamen initialisiert wird:

class GroupMembers(object):
    """Context source binder to provide a vocabulary of users in a given
    group.
    """

    grok.implements(IContextSourceBinder)

    def __init__(self, group_name):
        self.group_name = group_name

    def __call__(self, context):
        acl_users = getToolByName(context, 'acl_users')
        group = acl_users.getGroupById(self.group_name)
        terms = []

        if group is not None:
            for member_id in group.getMemberIds():
                user = acl_users.getUserById(member_id)
                if user is not None:
                    member_name = user.getProperty('fullname') or member_id
                    terms.append(SimpleVocabulary.createTerm(member_id, str(member_id), member_name))

        return SimpleVocabulary(terms)

Benannte Vokabularien

Sollen Vokabularien nicht nur im Kontext verfügbar sein sondern als Komponenten, werden sog. Named Vocabularies erstellt. Diese werden als named utilities registriert werden und sind anschließend in einem Schema mit ihrem Namen referenziert werden. Damit lassen sich Vokabularien in eigenständigen Paketen erstellen.

VDEX-Vokabularien

collective.vdexvocabulary erlaubt die Verwendung von IMS VDEX-Vokabularien und bietet darüberhinaus noch weitere Vorteile wie:

  • i18n-Unterstützung, wie sie im IMS VDEX-Standard definiert ist.

  • Unterstützung für Sortierung auch von Unicode-Zeichen. sofern zope.ucol installiert ist

  • Einfache Registrierung mit zcml

  • Relationen wie sie im IMS VDEX-Standard spezifiziert sind

collective.elephantvocabulary

collective.elephantvocabulary ist ein Wrapper für zope.schema-Vokabularien wodurch diese keinen ihre Einträge mehr vergessen.

Autovervollständigung

plone.formwidget.autocomplete erweitert z3c.formwidget.query um ein nutzerfreundlicheres Interface für Felder bereitzustellen, bei dem nach der Eingabe von wenigen Zeichen bereits die möglichen Werte angezeigt werden.

Das Widget wird bereits mit plone.app.dexterity mitgeliefert, sodass wir es einfach z.B. in registration.py verwenden können, mit:

form.widget(organiser=AutocompleteFieldWidget)
organiser = schema.Choice(
        title=_(u"Organiser"),
        vocabulary=u"plone.principalsource.Users",
        required=False,
    )