Skip to topic | Skip to bottom
Home
Zope.CookBookr1.74 - 05 Dec 2007 - 08:16 - FrankBurkhardt [Zum Ende]

Start of topic | Direkt zum Menü

Das MPI-Zope3-Kochbuch

Zope und Python bringen eine riesige Klassen/Komponenten-Bibliothek mit. Leider muss man diese Bibliothek komplett kennen, um zu wissen, was man eigentlich machen muss, wenn man ein gegebenes Problem hat. In diesem Wiki-Topic sollen nun Hinweise und Lösungen aufgezeigt werden, ausgehend von speziellen Problemen.

Zugriff auf bestimmte Objekte

Oft hat man in Zope3 das Problem habe Objekt vom Typ X, brauche Objekt vom Typ Y . Hier ist eine Sammlung solcher Probleme mit entsprechenden Lösungen.

Den RootFolder

Der root-Folder ist das Grundverzeichnis der Daten in der ZodB. Es gibt mehrere Möglichkeiten, um auf diesen zuzugreifen.

Den RootFolder kann man in Python und auch in Tal (also in PageTemplates) ermitteln.

Ausserdem kann man den RootFolder auch über eine manuell gestartete zusätzliche TransAction erhalten - siehe RootFolder#NewTransaction .

Eine bestimmte VieW eines Objektes

... In Python

Eine VieW läßt sich erzeugen, wenn man 3 Dinge hat: Ein Objekt context , einen ReQuest request , der evtl. schon zu einer anderen VieW gehört, und den Namen name der gesuchten VieW . Im Kochbuch ist auch beschrieben, wie man z.B. den passenden name der default- VieW ermittelt.

from zope.app import zapi
myview=zapi.queryMultiAdapter((context,request),name=name)

... in TaLes (also in einem PageTemplate)

In TaLes kann man mit der @@-Notation in Path-Expressions leicht VieWs bilden.

Beispiel:

<div tal:content="context/@@name_der_view" />

Das geht auch z.B. mit Unterobjekten eines Containers:

<div tal:repeat="subobject python: context.values()">
   <a tal:attributes="href subobject/@@absolute_url" tal:content="subobject/__name__" />
</div>

Der HTTP-Header

Der HTTP-Header hängt am ReQuest-Objekt. Das geht aus allen BrowserViews heraus - auch innerhalb von PageTemplates - z.B. so:

<div tal:content="request/PATH_INFO"

Welche Felder und Informationen genau zur Verfügung stehen, findet man leicht herraus, indem man sich das ReQuest -Objekt mit dir(request) oder print request genauer ansieht.

HTTP-Formular-Daten

Siehe HttpForms.

Das Request-Objekt

Das ReQuest-Objekt steht in PageTemplates (siehe ReQuest#GetTal ) und in VieWs (siehe ReQuest#GetFromView ) zur Verfügung.

Wie man das ReQuest-Objekt aus dem Nichts ermitteln kann, ist unter ReQuest#GetMagic beschrieben.

Ein bestimmtes UtilitY

Siehe UtilitY#GetOne .

Namen herrausfinden

... aller Utilities, die ein bestimmtes Interface erfüllen

Siehe UtilitY#UtilityList .

... eines Objektes als UrL

Für alle ContentObjects, die im Content-Baum der ZodB liegen, kann die eindeutige UrL ermittelt werden. Verantwortlich dafür ist, dass diese Objekte sog. LocationNs? sind. Das selbe gilt auch für alle BrowserViews.

In einem PageTemplate

Es existiert eine BrowserView, für alle ContentObjects: absolute_url . Diese kann man z.B. im Browser selbst aufrufen (was nicht viel Sinn macht):

http://server/meinobjekt/absolute_url

Da sich alle BrowserViews in PageTemplate mit der AtAt -Notation einbinden lassen, kann man auch solche Konstruktionen wagen:

<div tal:content="context/@@absolute_url" />
<a tal:attributes="href string:${context/@@absolute_url}/edit.html">Dieses Objekt bearbeiten</a>
<a tal:repeat="subobject context"
   tal:attributes="href string:${subobject/@@absolute_url}"
   tal:content="string:Objekt ${subobject/__name__} bearbeiten" />

In Python

from zope.app import zapi

url=zapi.absoluteURL(mein_objekt,request)

Hinweise:

  • Eine UrL kann nur dann gebildet werden, wenn ein ReQuest -Objekt vorhanden ist - es geht definitv nicht ohne.

In Python ohne passendes ReQuest-Objekt

Ohne ReQuest kann man keine absolute URL berechnen, allerdings ist folgende Lösung recht brauchbar und liefert eine UrL relativ zum RootFolder (z.B. /calendar/event.html ):

from zope.app import zapi

def getUrl(obj):
   return zapi.getPath(obj)

ContentObjects

Ermitteln der bereitgestellten Interfaces

Siehe InterFace#ObjectsInterfaces.

Ermitteln aller bereitgestellten SchemaFields

Dazu kombiniert man die Möglichkeiten unter InterFace#ObjectsInterfaces und InterFace#GetFields .

Achtung: Objekte implementieren teils sehr viele InterFaces, wovon etliche keinen Content beschreiben (z.B. ILocation von LocatioN-Objekten ).

Objekte mit komplexen Datenstrukturen

Zope ist in der Lage, Content in einzelnen Objekten zu speichern, der komplexer als eine reine Menge von Feldern ist. z.B. können Felder auch aus Listen bestehen, deren Einträge jeweils wieder Mengen von Feldern sind. Weiteres dazu gibt's unter KomplexerContent.

Achtung: Wird der Content zu komplex, sollte man ihn Form von Containern und enthaltenen Objekten abbilden.

Objekte mit grossen Datenmengen

Das z3c.extfile -Paket speichert grosse Datenmengen im Filesystem, wobei nur eine Referenz in der ZodB abgelegt wird: http://svn.zope.org/z3c.extfile/trunk/src/z3c/extfile/ .

Einfache benutzer-editierbare Webseiten

Wenn man einfach nur statische Seiten braucht - vielleicht sogar unter Benutzerkontrolle, kann man entweder ZPT-Objekte benutzen. Man kann sich aber auch der verschiedenen Renderer von Zope bedienen. Diese gestatten - ähnlich wie in einem Wiki - ohne HTML-Kenntnisse - Seiten (auch mit Stil-Elementen) zu erstellen. Solche Funktionalität läßt sich auch leicht in eigene ContentObjects einbauen.

Eine Beispielimplementation gibt's unter MpgSiteSimplepage .

Mehrsprachige Felder in ContentObjects

Unter FbI18n ist eine spezielle Datenstruktur beschrieben, mit der man verschiedene Sprachversionen von wahlfreien Datenfeldern (z.B. TextLine oder SourceText) verwalten kann. Damit ist es auch möglich mehrsprachige Daten und sprachunabhängige Daten (z.B. Datumsangaben) in einem Objekt zu kombinieren.

Versionskontrolle an Objekten

Zope bringt dafür das Paket zope.app.versioncontrol mit.

WorkFlow mit Objekten

Die Wikiseite WorkFlow läßt sich darüber aus.

Container

Automatisch Unterobjekte in einen neuen Container legen

Automatisch Unterobjekte in einem ConTainer anlegen, der gerade erst erzeugt wurde, ist etwas tricky. Unter ConTainer#AutoSubobjects ist die Problematik sammt lösung beschrieben.

Anlegen von Objekten durch nicht authentifizierte Benutzer

Siehe AddingView#AddingPermission

Löschen von mehreren (oder allen) Unterobjekten

Dabei gibt es einiges zu beachten. Informationen gibt's unter ConTainer#MassDeletion .

Umbenennen von Objekten im ConTainer

Dafür gibt's ein spezielles InterFace, das wie folgt benutzt wird:

from zope.copypastemove.interfaces import IContainerItemRenamer

def rename_object(container,oldname,newname):
   icir=IContainerItemRenamer(container)
   renameItem(oldname,newname)

Wenn der neue Name schon bzw. der alte nicht vorhanden ist, gibt's eine ExCeption .

Fein granulierte Berechtigungen (z.B. Anlegen, aber nicht Löschen...)

Oft ist es sinnvoll, die Berechtigungen zum Anlegen und zum Löschen von Objekten in einem ConTainer unterschiedlich zu behandeln, so dass z.B. anonyme nutzer Objekt anlegen aber nicht wieder Löschen oder auch nicht wieder lesen dürfen (ähnlichen einem FTP-Incomming-Verzeichnis).

Unter ConTainer#GranularRights ist beschrieben, wie das geht.

Anlegen eines Objektes in einem ConTainer mit automatischer Namenswahl

Unter ConTainer#NameChooser ist beschrieben, wie man Zope die Namenswahl über neue Unterobjekte überläßt.

Anlegen eines Objektes im Browser ohne automatische Namenswahl

Üblicherweise legt man im AddForm fest, welchen Namen ein neues Objekt erhalten soll. Läßt man das Namensfeld frei, wird ein Name automatisch vergeben (per NameChooser). In bestimmten Situationen hätte man gerne mehr Kontrolle über den vergebenen Namen - wie das geht, ist unter AddForm#NameSelection beschrieben.

Im ZmI können in einem Container keine Unterobjekte angelegt werden. Was kann man tun?

Vielleicht wurde vergessen, die <browser:containerViews> -Direktive im ZcmL zu definieren?. Ohne diese hat das ZmI keinen Zugriff auf die ConTainer .

Wie bekommt man eine Liste der möglichen Unterobjekt-Typen?

Das ist unter ConTainer#ValidSubobjects beschrieben.

VieWs

Rendern von Text

Unter Rendern von Text versteht man das Umrechnen von einer Textform (z.B. Twiki-Quelle, StructuredText, RestructuredText oder auch reiner ASCII-Text) in etwas anderes. Das bedeutet üblicherweise, dass man den Text aus der Speicherform (Quelle) in die Transportform (z.B. XHTML) überführen will.

Zope3 bringt ein Konzept mit, das folgendes Umfasst:

  1. Source-Text wird in ein spezielles Objekt umgewandelt, das ein vone zope.app.renderer.interfaces.ISource abgeleitetes Source-Format-spezifisches InterFace (z.B. zope.app.renderer.rest.IReStructuredTextSource erfüllt.
  2. Ein VieW, die sich auf dieses InterFace und auf den aktuellen ReQuest versteht (das ist meistens HTML) macht aus dem Source-Objekt einen UniCode -String - den gerenderten Text.
  3. Diesen String gibt man in der aktuellen VieW zurück.

Und so wird's gemacht:

from zope.security.proxy import removeSecurityProxy

class MyView(BrowserView):
   def __call__(self):
      rest=zapi.createObject(None,'zope.source.rest',self.context.my_restrucuted_textstring)
      view=getMultiAdapter((removeSecurityProxy(rest),request),IBrowserView,'')
      html=view()
      return html

Einen eigenen Renderer schreiben

Wenn man ihn wie ein Plugin in das Renderer-Framework integrieren will, muss man lediglich eine FactorY, die das zope.app.renderer.interfaces.ISource -Objekt erzeugt, und die Renderer-VieW schreiben. Die Renderer-VieW ist dabei das eigentlich Arbeitstier - sie geht den Quelltext Zeile für Zeile durch und baut daraus z.B. HTML. Man kann aber z.B. auch einen externen Renderer aufrufen (z.B. ein Shellkommando).

MpgSite bringt einen Renderer mit, der Twiki-Sourcen in valides XHTML verwandelt ( FbTwiki ). Dieser Renderer nimmt auch zusätzliche Informationen wie das aktuelle ContentObject entgegen, um z.B. Bilder einzubinden.

Eine Umleitung schicken

Siehe BrowserView#HttpRedirect

Zurückliefern statische Objekte

Oft werden statische Objekte benötigt - z.B. Icons oder CSS-files. Für diese will man nicht eigene VieWs schreiben. Das muss man auch nicht, denn es gibt Browserresourcen.

Zurückliefern bestimmter Inhaltetypen (z.B. Bilder)

Eine VieW kann beliebige Daten zurückliefern - also auch z.B. ein in Echtzeit errechnetes Bild. Dazu muss man manuell den Content-Typ setzen, wobei man den MIME-Type der Daten kennen muss.

Ein Beispiel:

views.py

from zope.app.publisher.browser import BrowserView
class PictureView(BrowserView):
   def __call__(self):
      self.request.response.setHeader('Content-Type','image/jpeg')
      return self.content.picture_jpeg

Hinweise:

  • Das Datenfeld picture_jpeg muss auf jeden Fall ein ganz normaler str -String sein - also z.B. nach dem BytesLine -Schema (siehe SchemaInterFaces) - kein UniCode-String.
  • Kennt man den MIME-Type nicht, kann man die libmagic benutzen - wie z.B. in FbFile .

Zurückliefern grosser Datenmengen

Zope unterstützt den Transfer grosser Datenmengen währende eines ReQuests zum Benutzer, die nicht komplett im Speicher liegen müssen (BloBs). Dazu muss die VieW lediglich anstelle von UniCode ein File-Objekt zurückliefern.

filmview.py

from zope.app.publisher.browser import BrowserView

MOVIE_FOLDER="/DATA/movies"

class FilmDownload(BrowserView):
   def __call__(self):
      fileobj=open(MOVIE_FOLDER + "/" + self.request['moviename'] + ".avi",'rb')
      self.request.response.setheader('Content-Type','video/x-msviewo')
      return fileobj

Hinweise:

  • Es versteht sich von selbst, dass der open-Aufruf besser abgesichert werden muss. Bei diesem Beispiel sind z.B. Angriffe durch .. -Komponenten in der per ReQuest übergebenen Variable sehr leicht machbar.

Downloadbare VieWs

Manchmal will man explizit, dass Daten eines VieWs heruntergeladen und nicht im Browser angezeigt werden. Das kann z.B. ein grosses Bild sein, dessen Anzeige einen Browser überfordern würde.

Mit dem Content-Disposition -HTTP-Header ist es möglich, den Browser nicht nur anzuweisen, den Link downzuloaden (und nicht anzuzeigen) - man kann auch noch einen Dateiennamen vorschlagen.

Ein Beispiel:

views.py

from zope.app.publisher.browser import BrowserView

class BigPictureView(BrowserView):
   def __call__(self):
      self.request.response.setHeader('Content-Type','image/jpeg')
      self.request.response.setHeader('Content-disposition','attachment; filename=bigimage.jpg')
      return self.content.generate_big_picture_jpeg()

Hochladen grosser Datenmengen (z.B. 100MB) ins Zope

Zope ist nicht geeignet, grosse Datenmengen in HTTP-ReQuests zu akzeptieren, da diese immer erst komplett in den Speicher müssten. Ein apache-Plugin kann da weiterhelfen:

http://www.infrae.com/products/tramline

Formulare

Weiterleitung nach Hinzufügen eines Objektes

Wenn die <addform -ZcmL-Direktive benutzt wurde, um ein Formular automatisch aus einem Schema-InterFace zu erzeugen, will man den Benutzer nach dem Hinzuügen des Objektes evtl. an eine bestimmte URL verweisen (z.B. eine mit dem textuellen Hinweis, dass alles funktioniert hat).

Die Methode nextURL der assoziierten VieW-Klasse kann dafür benutzt werden, wobei man jedoch beachten muss, dass man in dieser Methode keinen direkten zugriff auf das context -Objekt hat. Beispiel:

views.py:

class AddViewClassMixin(object):
   def add(self,content):
      located = self.context.add(content)
      self.absURL = zapi.absoluteURL(located, self.request)
      return located

   def nextURL(self):
      return self.absURL + '@@successful_added.html'

configure.zcml:

[...]
<addform
   label="New MyObject object"
   name="add_myobject.html"
   schema="interfaces.IMyObject"
   class="views.AddViewClassMixin"
   permission="zope.ManageContent"
/>
[...]

Weiterleitung nach Bearbeitung eines FormLib -Formulares

Dazu ist eine eine zusätzliche Methode in der (FormLib -) VieW-Klasse des Formulares nötig:

from zope.formlib import form

class MyFormView(form.EditForm):
[...]
   def render(self):
      if self.errors is None or self.errors:
         return super(myFormView,self).render()
      self.request.response.redirect(my_new_url)
[...]

PageTemplates

Javascripts mit Markup produzieren Fehler

Wie man Probleme vermeidet, die beim Einbetten von JavaScript-Code in PageTemplates entstehen, ist unter PageTemplate#EmbeddedJavascript beschrieben.

Python-Module aus PageTemplates herraus nutzen

Wie das geht, ist unter PageTemplates#PythonModules beschrieben.

PageTemplates für anderen Content als Webseiten

PageTemplates lassen sich für alle Arten von Dokumenten benutzen, die auf XML basieren - z.B. RSS-Feeds. Hinweise und ein Beispiel gibt's unter PageTemplates#ArbitraryXml.

Feststellen, ob der aktuelle Benutzer authentifiziert ist

Siehe PrinCipal#IsAuthenticated .

Eindeutige IDs für HTML-Tags

Formulare erzeugen automatisch eindeutige IDs - InputWidgets beherrschen das von Haus aus. Beim Anzeigen von Daten muss man selbst Hand anlegen. Wie das geht, ist unter KomplexerContent#UniqueLabels beschrieben.

"Dienste" für den Webauftritt

Hier werden Dinge erklärt, die Objektübergreifend von interesse sind - z.B. Erzeugung von Indizes oder Suchmaschinen.

Globale Konfigurationsparameter

Will man parameter einer ZopeInstance vorgeben (z.B. eMail-Adresse des Webmasters, ...), kann man das in einem Browserkonfigurierbaren UtilitY machen. Ein Beispiel dafür ist MpgSiteMpgconfig - ein UtilitY, das internationalisierte Bezeichnungen (Herr, Mr. , Monsieur, ...). Eine etwas einfachere Methode ist unter ZcmL#GlobalConfiguration beschrieben.

Webseiten in Druckansicht

Oft ist es sinnvoll, von einer Website eine Druckansicht zu zeigen. Man kann (und sollte) dabei viel mit CSS machen, jedoch kann zumindest CSS 2.0 noch nicht genug. Das Paket MpgSite enthält zusätzliche Unterstützung um ContentObjects druckfreundlich darzustellen: MpgSitePrintable .

Regelmäßig ausgeführte Aufgaben

Zope3 kennt keinen eigenen Mechanismus, um Aktionen zu gegebenen Zeiten anzustoßen. Üblicherweise benutzt man dafür cron und wget , um ein VieW eines Objektes aufzurufen. Auch der Aufruf per cron und XmlRpc ist denkbar.

Es existieren auch einige Methoden, getimte Methodenaufrufe direkt in den Zopeserver zu integrieren, jedoch wird im allgemeinen davon abgeraten.

Suchen

Realisieren einer Volltextsuche

Wie man eine Volltextsuchmaschine aufsetzt, wird unter SuchenImZope beschrieben.

Objekte finden, die vor dem IntId- UtilitY angelegt wurden

ContentObjects, die angelegt wurden, bevor ein IntId- UtilitY registriert war, werden von einer Suchmaschine nicht gefunden. Man kann das mit etwas Aufwand nachholen - mehr dazu unter IntId#MissingIds .

Schöne UrLs

Wie man die UrLs des eigenen Webauftritts so gestaltet, dass sie nicht vor Sonderzeichen strotzen, sondern schön aussehen, ist unter NiceUrls beschrieben.

Ein Navigationsmenü

Ein einfaches Navigationsmenü erstellt man, indem man es einfach in das PageTemplate -File schreibt, das das view - bzw page -Makro (siehe MeTaL ) des aktuellen SkiNs enthält. Dieses Menü ist dann aber statissch. Ein dynamisches Menü wir ebenfalls in das view -Makro integriert, bindet dann aber z.B. eine VieW ein, in der das ReQuest -Objekt ausgewertert wird, um das Menü entsprechend der aktuellen UrL anzupassen. Das Paket MpgSite hat dafür eine lösung parat: MpgSiteAutoMenu .

Eine leere ZodB initialisieren

Hat man eine neue ZopeInstance mit einer leeren ZodB, kann man sich an das zope.app.appsetup.IDatabaseOpenedEvent -EvenT anhängen, testen, ob der RootFolder noch leer ist und bei Bedarf ContentObjects anlegen, die eine bestimmte Anwendung aufspannen.

Fehlerbehandlung

Wie passt man die Fehlermeldungen in Zope3 an?

Alle Fehlermeldungen, die unter Zope3 angezeigt werden, basieren darauf, dass man (oder auch irgendein Fremdprodukt) in Python einen event raise d . Zope versucht, anhand des events eine VieW zu finden und zeigt diese an - siehe CustomMessages

Fehler Behandeln, aber Änderungen teilweise speichern

Es ist möglich, per ExCeption einen Fehler an Zope zu melden, die aktuelle TransAction und damit alle im ReQuest gemachten Änderungen zurückzunehmen und trotzdem einige Daten in der ZodB zu speichern.

Unter TransAction#SingleObject is beschrieben, wie das geht.

Sicherheit

Zope läßt den Manager nicht mehr rein

Es kommt vor, dass man sich aus Zope komplett aussperrt, indem man das Authenticator-Utility falsch konfiguriert. Beheben läßt sich das, indem man dem Authenticator-Utility die Registrierung entzieht.

Testen, ob man eine bestimmte Berechtigung an einem Objekt besitzt

Siehe PerMission#CheckPermission .

Testen, ob man das Recht hat, auf ein bestimmtes Attribut zuzugreifen

Wie das geht ist unter PerMission#CanAccess beschrieben.

Testen, ob der aktuelle Benutzer angemeldet ist

So testet man, ob der aktuelle Benutzer anonym ist:

from zope.app.security.interfaces import IUnauthenticatedPrincipal
anonymous=IUnauthenticatedPrincipal.providedBy(request.principal)

Alle nicht anonymen Benutzer sind auf die eine oder andere Weise authentifiziert.

Objekte, Klassen, Komponenten

Registrieren einer Komponente per Python

Siehe ZopeComponents#RegistrationPython .

Ermitteln der Felder eines InterFaces

Siehe InterFaces#GetFields.

Hinzufügen von Marker-InterFaces zu existierenden Klassen

Marker-Interfaces lassen sich an existierenden (Fremd-)Klassen durch ein zusätzliches ZcmL - <class> -Statement anhängen. Ganz allgemein kann man beliebig viele class-Statements pro Klasse haben - solange man nicht z.B. ein Attribut mehrfach definiert - dann muss man auf ZcmL#OverRide zurückgreifen.

Ermitteln aller der ZopeInstance bekannten InterFaces

Siehe InterFaces#ListAll.

Sicherstellen, dass ein bestimmtes Utility existiert

Mit folgender Methode kann man sicherstellen, dass ein bestimmtes Utility existiert (am Beispiel des IntID?-Utilities):

from zope.app.appsetup.bootstrap import ensureUtility
from zope.app.intid.interfaces import IIntIds

ensureUtility(context, IIntIds, '', IntIds, copy_to_zlog=False)

Mehrstufiges Adaptieren

Zope baut von sich aus keine Kette von Adaptern auf. Einige Hinweise dazu gibt's unter ZopeComponents#AdapterChain .

Einem ContentObject dynamisch ein InterFace zuweisen

Wie das geht, ist unter InterFace#MarkerInterfaces beschrieben.

Ereignissbehandlung

Vermeidung mehrfacher Ereignisbehandlung

Wie man vermeidet, dass nicht-idempotente Operationen im Rahmen einer Aktion mehrfach per EvenT aufgerufen werden, ist unter EvenT#MultipleEvents beschrieben.

Netzwerkverhalten

Beschränken der ZopeInstance auf bestimmte IPs/Ports

Siehe ZopeInstance#NetWork.

Fehlermeldungen (Zope-interne ExCeptions)

ForbiddenAttribute

Alle Objekte sind unter Zope mit jeweils einem SecurityProxy -Objekt gesichert. Der SecurityProxy gibt Zugriffe auf Methoden und Attribute des Objektes nur im Rahmen der vorher per ZcmL definierten Rechte, die der jeweilige Benutzer hat, frei. Mehr dazu gibt's unter SecurityProxy#ForbiddenAttribute.

UnpickleableError

Dieser Fehler tritt meist auf, wenn man ein per SecurityProxy gesichertes Objekt an ein anderes Objekt (z.B. als Attribut) anhängen will. Mehr dazu unter ContentObject#UnpickleableError .

NotYet

Dieser Fehler tritt immer dann auf, wenn versucht wird, eine KeyReference von einem ContentObject zu ermitteln, dass noch keine hat - sprich: das noch nicht in der ZodB abgelegt wurde.

Prominenter Schuldiger für diesen Fehler ist das IntId - UtilitY, dass sich jedes in einen ConTainer gelegte ContentObject hernimmt und dessen KeyReference in einem Index ablegt. Unter ConTainer#AutoSubobjects ist eine Lösung für dieses Problem skizziert.

POSKeyError

Wenn in der ZODB eine Inkosistenz auftritt, wird dieser Fehler gemeldet - jedoch nur ans Logfile: der Benutzer sieht etwas in der Art von System Error occured . Es ist keine Methode bekannt, das Problem automatisch zu beseitigen - jedoch gibt es hier einige Tips: PosKeyError .
[Zurück zum Start]


Aktuelle Wiki-Seite: Zope > CookBook

[Zurück zum Start]

Alle Inhalte dieses Web dürfen frei kopiert und verändert werden.