.. index:: z3c.form, z3c, formui, form, formui Formulare mit z3c.form ********************** Der nächste logische Schritt ist das Hinzufügen von neuen Kontakten mit einem Formular für Vorname und Nachname. Dieses Formular kann mit dem Schema (``IContact``) aus ``interfaces.py`` generiert werden, wenn Sie die ``z3c.form``-Komponente verwenden. .. index:: buildout Verfügbar machen von z3c.form and z3c.formui ============================================ Vor der Verwendung von z3c.form muss die Komponente in die Anwendung integriert werden. Dies erreichen Sie, indem Sie die Datei ``setup.py`` öffnen und ``'z3c.form' zum ``install_requires``-Parameter (etwa bei Zeile 25) hinzufügen. Für die Darstellung des Layouts sollten auch noch die Komponenten ``z3c.formui`` und ``z3c.layer`` in das System integriert werden. Danach muss noch die Konfiguration für ``z3c.form`` und ``z3c.formui`` in der Datei ``zcontact/src/zcontact/configure.zcml`` erfolgen. ``z3c.form`` nutzt zahlreiche andere z3c-Komponenten, welche wiederum neue zcml-Direktiven zur Verfügung stellen. Um diese Direktiven später nutzen zu können, sind die Meta-Dateien am Anfang von ``configure.zcml``, *noch vor den anderen include-Anweisungen* einzufügen: .. sourcecode:: xml Danach sollten dann am Ende der Datei ``configure.zcml`` die Komponenten ``z3c.form`` and ``z3c.formui`` eingefügt werden: .. sourcecode:: xml Sie müssen jetzt den Buildout-Prozess erneut starten, damit die neuen egg-Pakete für ``z3c.form`` und ``z3c.formui`` heruntergeladen und verfügbar gemacht werden. Starten Sie den Vorgang einfach mit:: $ ./bin/buildout -Nv Mit der Option ``-N`` verhindern Sie das nochmalige Herunterladen von Paketen, die Sie bereits haben (und das ist nur zu empfehlen). Konfiguration der Anwendung für die Benutzung von z3c.form =========================================================== Leider ist die Nutzung von z3c.form noch nicht möglich. Weil die z3c-Komponenten ein etwas anderes Muster für die Anwendungsentwicklung verwenden, sind einige zusätzliche Arbeitsschritte notwendig, um eigene Anwendungen zum Laufen zu bringen. Einer dieser Schritte ist die Erstellung eines eigenen Layer und Skin. Leider zwingen Sie die meisten zcml-Direktiven nicht zur direkten Angabe des zu verwendenden Layer, wenn eine Seite oder Sicht (View) registriert wird. Wenn Sie keinen Layer angeben, wird die Seite für den Standard-Layer erzeugt. Es bleibt festzuhalten, dass viele Komponenten (inclusive Rotterdam) ihre Sichten für den Standard-Layer registrieren, was diesen Layer mit unötigen Dingen überfrachtet, die nicht gebraucht werden. Um diese Überfrachtung zu vermeiden registrieren alle z3c-Komponenten ihre Sichten an speziellen komponenten-spezifischen Layern. Die mit den z3c.*-Komponenten gelieferten Layer müssen für die eigenen Komponenten erweitert werden. Deshalb erstellen Sie einen eigenen Layer, der es erlaubt, die Sichten der z3c-Komponente zu verwenden. .. index:: z3c.layer Definition eines Layer ----------------------- Erstellen Sie eine neue Datei , ``src/zcontact/layer.py`` und fügen Sie den folgenden Code hinzu: .. sourcecode:: python from z3c.form.interfaces import IFormLayer from z3c.layer.pagelet import IPageletBrowserLayer class IZContactBrowserLayer(IFormLayer, IPageletBrowserLayer): """ZContact browser layer with form support.""" ``IFormLayer`` hat Sichten für alle Widgets die in den generierten Formularen verwendet werden, und ``IPageletBrowserLayer`` liefert einige Fehler-Seiten und andere nützliche Ausgaben. .. index:: skin Einen Skin erstellen -------------------- Für den Zugriff auf den Layer über den Browser wird ein Skin verwendet. Erstellen Sie dazu eine weitere Datei, ``src/zcontact/skin.py`` und fügen Sie den folgenden Code ein: .. sourcecode:: python import z3c.formui.interfaces from zcontact import layer class IZContactBrowserSkin(z3c.formui.interfaces.IDivFormLayer, layer.IZContactBrowserLayer): """The ZContact browser skin using the div-based layout.""" Beachten Sie, dass unser Skin vom ``IDivFormLayer`` erbt, der in der ``z3c.formui`` Komponente definiert ist. Wenn die Formulare erzeugt werden, sind die Felder in ``
`` Tags und nicht in einer Tabelle eingebettet. Es gibt einen weiteren Layer, für ein tabellenbasiertes Layout. Dank der Komponenten-Architektur wäre es auch möglich einen eigenen Layout-Layer zu schreiben, aber das soll jetzt gezeigt werden. Nun müssen Sie den Skin mit einer neuen Datei ``src/zcontact/skin.zcml`` registrieren. Der Skin kann dann wie folgt verwendet werden: http://localhost:8080/++skin++ZContact/ und der Inhalt der Datei sieht wie folgt aus: .. sourcecode:: xml Bitte nicht vergessen in die neue zcml-Datei ``zcontact/configure.zcml`` die folgende Zeile einzufügen: ````. .. index:: add form Ein Formular für die Neuanlage ============================== Sie beginnen mit der Erstellung eines neuen Modules ``zcontact.browser``, durch Anlage eines Ordners unterhalb von ``src/zcontact/``. Der Ordner ``browser`` erhält eine leere Datei ``__init__.py`` . Danach erstellen Sie die Datei ``zcontact/browser/contact.py`` in der alle Formulare definiert werden. Beginnen Sie mit dem Einfügen des folgenden Codes in die Datei ``browser/contact.py``: .. sourcecode:: python from z3c.form import form, field from zcontact import interfaces class ContactAddForm(form.AddForm): """A simple add form for contacts.""" fields = field.Fields(interfaces.IContact) Die Klasse ``form.AddForm`` von der geerbt wird, definiert einige Methoden, für das Hinzufügen und Anlegen unserer neuen Objekte, die Sie später überschreiben werden und einige typische Schalter für ein solches Formular. Als nächstes wird eine Seite erstellt, die unsere Klasse verwendet und das Formular zur Anzeige bringt. Öffnen Sie die Datei ``zcontact/browser/configure.zcml`` und fügen Sie folgendes hinzu: .. sourcecode:: xml Das Browser-Modul muß nun am Ende der Datei ``zcontact/configure.zcml`` durch Hinzufügen der folgenden Zeile ```` bekannt gemacht werden. Für den Test wird jetzt der Server mit ``./bin/paster serve deploy.ini`` (oder ``debug.ini`` wenn Sie möchten) gestartet und im Browser die folgende Seite aufgerufen: http://localhost:8080/++skin++ZContact/@@addContact.html. Hier wird eine Seite mit dem Namen addContact.html für das IFolder-Interface registriert. Weil jeder Root-Ordner das Interface IFolder implementiert, sollte das folgende Formular angezeigt werden: .. image:: images/addFormSimple.png Das Formular vollenden ====================== Wenn Sie gerade versucht haben das Formular abzuschicken, indem Sie auf den add-Schalter geklickt haben, sollten Sie eine Fehlermeldung ``NotImplemented`` erhalten haben. Wenn Sie paster mit debug.ini statt deploy.ini starten, erhalten Sie vielleicht eine etwas schönere Ausgabe wie hier gezeigt: .. image:: images/serverError.png Mit dieser Ausgabe können Sie jede Zeile im traceback erweitern und Python-Code eingeben um das Probem zu untersuchen. Ich war sehr beeindruckt, als ich diese Möglichkeit das erste mal sah. Um das Problem beheben zu können, müssen drei Methoden für die Klasse ``ContactAddForm`` implementiert werden: ``create``, ``add`` und ``nextURL``. Um es kurz zu halten, kann es wie folgt implementiert werden, Sie können aber auch einen anderen Weg wählen. .. sourcecode:: python from z3c.form import form, field from zcontact import interfaces from zcontact.contact import Contact class ContactAddForm(form.AddForm): """A simple add form for contacts.""" fields = field.Fields(interfaces.IContact) def create(self, data): contact = Contact() form.applyChanges(self, contact, data) return contact def add(self, contact): self._name = "%s-%s" % (contact.lastName.lower(), contact.firstName.lower()) self.context[self._name] = contact def nextURL(self): return '/' In der create-Methode, beutzen Sie ``form.applyChanges`` zum Speichern der Attribute für ``firstName`` und ``lastName`` eines neuen Kontakt-Objektes. Die Daten, die an die create-Methode übergeben werden, sind eine Zuordnung von Feldnahmen zu den eingegebenen Werten (Mapping) und bereits in die richtigen Python-Datentypen konvertiert. Es gibt auch folgende Möglichkeit: ``contact.firstName = data['firstName']``. In der ``nextURL``-Methode ist ein hart-codierter Pfad anzugeben, der die Anwendung zum Rotterdam-Standard-Skin umschaltet und dort sollten Sie in der Inhalts-Ansicht den neu erstellten Kontakt sehen können. Dies ist erforderlich, weil wir noch keine eigene Inhalts-Ansicht für den eigenen Layer/Skin geschrieben haben. .. index:: display form, edit form Formulare für die Anzeige und Bearbeitung ========================================= Anzeige- und Bearbeitungs-Formulare sind einfacher als Formulare für die Neuanlage, weil keine Methoden implementiert werden müssen. Beginnen Sie mit einem Anzeige-Formular. Erstellung eines Anzeigeformulars --------------------------------- Für das Anzeige-Formular wird eine neue Klasse benötigt, die von ``form.Form`` erbt. Um die Formular-Bestandteile (Widgets) als reinen Text und nicht als Eingabefelder darstellen zu können, muß der Modus für das Formular auf ``DISPLAY_MODE`` gesetz werden. Es ist eine Konstante, die von ``z3c.form.interfaces`` importiert werden kann. Öffnen Sie ``zcontact/browser/contact.py`` und fügen Sie den folgenden Code ein: .. sourcecode:: python class ContactDisplayForm(form.Form): """A simple display form for contacts.""" fields = field.Fields(interfaces.IContact) mode = DISPLAY_MODE Vergessen Sie nicht, das neue Formular in ``configure.zcml`` wie folgt zu registrieren: .. sourcecode:: xml Nun, können Sie die ``nextURL``-Methode von ``ContactAddForm`` auf das neu erstellte Kontakt-Objekt zeigen lassen. Der Code sollte wie folgt aussehen: .. sourcecode:: python def nextURL(self): return absoluteURL(self.context[self._name], self.request) Vergessen Sie bitte nicht die folgende Zeile am Anfang der Datei einzufügen: ``from zope.traversing.browser.absoluteurl import absoluteURL`` Wenn soweit alles geklappt hat, sollte man nach einem Server-Neustart, mit der folgenden URL einen neuen Kontakt angelegt könenen, der dann zum Anzeige-Forumlar weitergeleitet wird: http://localhost:8080/++skin++ZContact/@@addContact.html Es sollte dann wie hier gezeigt aussehen: .. image:: images/DisplayFormScreenShot.png .. index:: buttons Schalter zum Formular hinzufügen -------------------------------- Nun wird das Formular um zwei Schalter ergänzt, einen zum Bearbeiten und den anderen zum Löschen eines Kontakt-Objektes. Beginnen Sie mit dem Hinzufügen der folgenden import-Anweisung am Anfang der Datei ``contact.py``. Wenn der Anwender auf einen der Schalter klickt, schickt er die Formulardaten zu einem definierten Attribut des Formulars. Standardmäßig wird die URL des Formulars selbst verwendet, wenn ein Schalter gedrückt wird und das Formular wird neu geladen. Wenn das Formular verarbeitet wird, prüft es, welcher Schalter gedrückt wurde und ruft den passenden "Akteur" auf, der als Methode der ``ContactDisplayForm``-Klasse definiert wird. Mit z3c.form definieren wir einen Schalter und den dazugehörigen Akteur durch Verwendung eines Dekorators. Der Löschen-Schalter soll den Kontakt entfernen und zum Hinzufügen-Formular zurückkehren. Deshalb fügen Sie bitte den folgenden Code zur Klasse ``ContactDisplayForm`` hinzu: .. sourcecode:: python @button.buttonAndHandler(u'Delete', name='delete') def handleDelete(self, action): name = getName(self.context) parent = getParent(self.context) del parent[name] nextURL = absoluteURL(parent, self.request)+'/@@addContact.html' self.request.response.redirect(nextURL) Am Anfang der Datei werden noch die folgenden Import-Anweisungen benötigt: .. sourcecode:: python from z3c.form import form, field, button from z3c.form.interfaces import DISPLAY_MODE from zope.traversing.browser.absoluteurl import absoluteURL from zope.traversing.api import getParent, getName Jetzt fügen Sie noch einen Bearbeiten-Button ('Edit') hinzu. Dafür gibt es noch kein Bearbeiten-Formular, dieser Schritt wir hier aber schon vorbereitet. Fügen Sie deshalb folgendes zur ``ContactDisplayForm``-Klasse hinzu: .. sourcecode:: python @button.buttonAndHandler(u'Edit', name="edit") def handleEdit(self, action): nextURL = absoluteURL(self.context, self.request) + '/@@editContact.html' self.request.response.redirect(nextURL) Starten Sie jetzt den Server neu und testen Sie die Schalter. Das Formular sollte wie hier gezeigt aussehen: .. image:: images/DisplayFormButtonScreenShot.png Die Erstellung des Bearbeiten-Formulars --------------------------------------- Der Vorteil der automatisch generierten Formulare sollte nun sichtbar werden. Der abschließende Schritt, für die Erstellung des Formulars, ist der einfachste von allen. Hier ist der notwendige Code: .. sourcecode:: python class ContactEditForm(form.EditForm): """A simple edit form for contacts.""" fields = field.Fields(interfaces.IContact) mit der dazugehörigen zcml-Konfiguration: .. sourcecode:: xml Probieren Sie nun das Bearbeiten-Formular aus, nachdem Sie das Anzeige-Formular aufgerufen haben. Beachten Sie den "Apply"-Schalter zum Abschicken der Daten. Als Anwort erhalten Sie eine Statusmeldung für den Erfolg oder Misserfolg der Speicheraktion. An dieser Stelle wollen wir aber zurück zum Hinzufügen-Formular, deshalb fügen wir noch einen "Done"-Schalter mit dem folgenden Code zur ``ContactEditForm``-Klasse hinzu: .. sourcecode:: python @button.buttonAndHandler(u'Done', name='done') def handleDone(self, action): self.request.response.redirect(absoluteURL(self.context, self.request)) Aber halt! Sobald man einen eigenen Schalter erstellt, werden die von ``form.EditForm`` Klasse definierten Schalter überschrieben. Um dies zu verhindern, wird die ``form.EditForm`` -Klasse *erweitert* indem Sie ``form.extends(form.EditForm)`` direkt hinter der ``ContactEditForm``-Klasse deklarieren. Sie sollten nun ein Bearbeiten-Formular erhalten, das wie folgt aussieht: .. image:: images/EditFormScreenShot.png Eine Startseite für die Anwendung ================================= Als vorläufigen Abschluss, erstellen Sie für die Anwendung eine Startseite, bevor Sie sich weiter mit dem "Skinning" beschäftigen. Die nächste Seite soll eine Startseite werden, die eine Möglichkeit zum Hinzufügen eines neuen Kontakts sowie jeweils einen Link zu den vorhandenen Kontakten enthält. Dies alles ist mit einem einfachen page template ``zcontact/browser/frontpage.pt`` möglich: .. sourcecode:: xml

Welcome to ZContact

Please tell me what you would like to do:

Dieses page template wird über zcml für das ``IRootFolder``-Interface registriert. Fügen Sie in ``zcontact/browser/configure.zcml`` folgende Zeilen hinzu: .. sourcecode:: xml Nach dem Server-Neustart kann die Startseite wie folgt getestet werden: http://localhost:8080/++skin++ZContact/ und Sie sollten in etwa die folgnede Ansicht erhalten: .. image:: images/FrontPageScreenShot.png Mit ein paar Formularen und einer funktionierenden Anwendung können Sie sich nun andere z3c.*-Komponenten ansehen.