Strumenti personali
Tu sei qui: Portale Scopri Documentazione Guide Sviluppare contenuti in Zope 3 e Plone 3
Azioni sul documento

Sviluppare contenuti in Zope 3 e Plone 3

Nota: questa è la vista stampabile contenente tutte le pagine della guida in una sola pagina. Se si preferisce c'è disponibile la versione suddivisa in più pagine.

Come sviluppare dei prodotti in Zope 3 utilizzando le FormLib.

Introduzione

Qualche annotazione prima di inizare

Componenti Richiesti

Gli esempi mostrati necessitano dei seguenti componenti:

  • Python >= 2.4.3
  • Zope >= 2.9.3
  • Plone >= 2.5
  • Five >= 1.4

Gli esempi descritti in questo tutorial possono funzionare con versioni differenti, ma l'autore non ha eseguito test e la strada da percorrere potrebbe essere molto lunga.

Qualche Annotazione Prima di Iniziare

Si inizia a lavorare partendo da un prodotto dal nome "ploneexample.formlib". Il codice completo per l'esempio può essere navigato usando il browser svn o scaricato usando Subversion attraverso il repository svn.

La prima cosa che uno sviluppatore Plone nota di insolito è il modo di chiamare il prodotto. Tradizionalmente i prodotti Plone usano la notazione CamelCase per i nomi in modo che non contengano punti (per esempio PloneFormLib). Ma in quanto uno degli obiettivi prefissati per questo tutorial, per un migliore esercizio verrà utilizzata la nuova notazione quando si proverà ad essere pythonic il più possibile usando le lettere minuscole per i nomi dei prodotti.

L'Importanza di Pythonic

La maggior parte di voi potrebbe chiedersi, "ma perchè bisogna preoccuparsi di essere pythonic?" La ragione più evidente  di mantenere lo stile pythonic è rendere le cose così semplici da essere comprese da chi ha già familiarità con Python.
Quando si sviluppano prodotti standard Zope 2 e vengono collocati nella directory Products dell'istanza Zope 2, Zope magicamente li inserisce nel namespace dei Products (per esempio il path del pacchetto CMFPlone attualmente diventa Products.CMPFlone). Inserire i prodotti nel PYTHONPATH come ogni altro package e renderlo riusabile in generale è una Buona Cosa TM.
Ancora, rendendo i prodotti in stile pythonic, è possibile usare dei tool generici di Python quali easy_install e setuptools (entrambi degli ottimi package di gestione dei componenti) per lavorare con questi prodotti.

Creazione del prodotto

Creazione del prodotto e sviluppo iniziale

Per la creazione iniziale del prodotto verrà usato un piccolo componente del progetto Python Paste. Per il resto di questo tutorial si presume che abbiato installato i prodotti setuptools e easy_install scritti da Phillip J. Eby. Così come il  componente paster insieme al package dei template ZopeSkel. Per le istruzioni su come configurare paster e ZopeSkel, si guardi l'eccellente articolo su ZopeSkel di Daniel Nouri.

Quindi, si parte:

$ paster create -t plone ploneexample.formlib
Selected and implied templates:
ZopeSkel#plone_core A Plone Core project

Variables:
package: ploneexampleformlib
project: ploneexample.formlib
Creating template plone_core
Enter namespace_package (Namespace package) ['plone']: ploneexample
Enter package (The package contained namespace package (like i18n)) ['']: formlib
Enter pythonproducts (Are you making a productsless Zope 2 Product?) [False]: True
Enter version (Version) ['0.1']:
Enter description (One-line description of the package) ['']: A Plone product for demonstrating zope.formlib usage
Enter long_description (Multi-line description (in reST)) ['']:
Enter author (Author name) ['Plone Foundation']: Rocky Burt
Enter author_email (Author email) ['plone-developers@lists.sourceforge.net']: rocky@serverzen.com
Enter keywords (Space-separated keywords/tags) ['']:
Enter url (URL of homepage) ['http://svn.plone.org/svn/plone/plone.i18n']: http://dev.plone.org/collective/browser/examples/ploneexample.formlib
Enter license_name (License name) ['GPL']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Recursing into +namespace_package+
Creating ./ploneexample.formlib/ploneexample/
Recursing into +package+
Creating ./ploneexample.formlib/ploneexample/formlib/
Copying HISTORY.txt_tmpl to ./ploneexample.formlib/ploneexample/formlib/HISTORY.txt
Copying LICENSE.GPL to ./ploneexample.formlib/ploneexample/formlib/LICENSE.GPL
Copying LICENSE.txt_tmpl to ./ploneexample.formlib/ploneexample/formlib/LICENSE.txt
Copying README.txt_tmpl to ./ploneexample.formlib/ploneexample/formlib/README.txt
Copying __init__.py_tmpl to ./ploneexample.formlib/ploneexample/formlib/__init__.py
Copying configure.zcml to ./ploneexample.formlib/ploneexample/formlib/configure.zcml
Copying version.txt_tmpl to ./ploneexample.formlib/ploneexample/formlib/version.txt
Copying __init__.py_tmpl to ./ploneexample.formlib/ploneexample/__init__.py
Copying setup.cfg to ./ploneexample.formlib/setup.cfg
Copying setup.py_tmpl to ./ploneexample.formlib/setup.py
Running /usr/bin/python2.4 setup.py egg_info


Iniziamo a sviluppare

Dopo questa operazione si dovrebbe ora avere una directory chiamata ploneexample.formlib nella directory corrente. Per le finalità di sviluppo verrà usato setuptools per configurare il progetto ploneexample.formlib nel PYTHONPATH in modo da poterlo rendere disponibile per Zope. Spostarsi nella directory del progetto ploneexample.formlib ed eseguire il seguente comando (ricordando di eseguirlo come sudo se si è in un ambiente UNIX e non si hanno i permessi sufficienti per scrivere nella directory site-packages di python):

$ python2.4 setup.py develop

Ci sarà un output simile al seguente:

[snip output...]
Installed /home/rocky/Documents/developing/projects/ploneexample.formlib
Processing dependencies for ploneexample.formlib==0.1dev

 

Inseriamo il Nuovo Prodotto in Zope 2

Ora che si ha a disposizione un prodotto per Zope 2 pienamente eseguibile, è possibile procedere con la sua configurazione all'interno dell'istanza Zope 2. Finchè Zope e CMF/Plone non verranno aggiornati (Zope 2.10 possiede già le modifiche necessarie), è necessario utilizzare il prodotto pythonproducts per abilitare i prodotti che risiedono all'esterno della directory Products dell'istanza Zope.

Scaricate ed installate pythonproducts seguendo le istruzioni che trovate nel prodotto. Per chi avesse fretta, l'installazione di pythonproducts consiste nel download del sorgente, la sua estrazione in una dir temporanea, e l'esecuzione del comando:

$ python2.4 setup.py install --home $INSTANCE_HOME

Ora è necessario attivare il package ploneexample.formlib quale prodotto Zope 2. Per fare ciò bisogna spostarsi nella directory etc/package-includes dell'istanza Zope 2 e creare un nuovo file chiamato ploneexample.formlib-configure.zcml il cui contenuto deve essere:

<include package="ploneexample.formlib" />

E' possibile ora provare l'instanza Zope 2 per avere la conferma che il nuovo prodotto ploneexample.formlib sia disponibile. Si può fare ciò eseguendo l'istanza Zope normalmente e verificare nella sezione Prodotti nel Pannello di Controllo della ZMI se il prodotto è correttamente installato. Dovrebbe essere visibile una cosa del tipo:

ploneexample.formlib (Installed product ploneexample.formlib)

Comprendere le FormLib

Costruzione di una semplice form di ricerca per i contenuti Plone.

zope.formlib è un package progettato per facilitare lo sviluppo di form web nelle proprie applicazioni Zope. Nella sua più semplice espressione, è possibile confrontare cosa genera formlib con la controparte auto-generata da Archetype che permette la visualizzazione di un contenuto (base_view) e la sua modifica (base_edit). In pratica, i componenti basati su formlib  sono dei normali componenti di visualizzazione Zope con alcune classi base per generare automaticamente risultati basati sullo schema e altre informazioni di configurazione.

Grazie alla sua inclusione in Zope 2.9.3, zope.formlib è ora distribuito con le release di Zope 2. Ovviamente, Five >= 1.4 è richiesto per eseguire correttamente questo package Zope 3.

 

Definire la Prima Form

Per gli scopi di questo tutorial, verrà costruita una semplice form di ricerca per i contenuti Plone. Questa form è simile a quella che si ottiene dalla Ricerca Avanzata di Plone, ma molto più semplice.

Il codice sorgente di questi esempi sono disponibili nel browser svn e nel repository svn .

 

La Classe Form

Si incomincia creando un nuovo file, browser.py, che deve risiedere in ploneexample.formlib/ploneexample/formlib/. Il file browser.py comprende tutto ciò che è necessario per lavorare correttamente. Aggiungiamo gli import necessari:

from zope import interface, schema
from zope.formlib import form
from Products.CMFCore import utils as cmfutils
from Products.Five.browser import pagetemplatefile
from Products.Five.formlib import formbase

Ora si passa alla costruzione dell'interfaccia Zope 3:

class ISearch(interface.Interface):
text = schema.TextLine(title=u'Search Text',
description=u'The text to search for',
required=False)

description = schema.TextLine(title=u'Description',
required=False)

 

Lo scopo dell'interfaccia in questo caso non è quello di descrivere un particolare content object, ma è quello di definire i campi che formlib userà. Più avanti si scoprirà come le tradizionali interfacce usate per descrivere le attuali classi di contenuti possono essere usate in combinazione con formlib per autogenerare propriamente i form di aggiunta e modifca dei contenuti.

E ora ecco la classe della form stessa. Si partirà dalla prima parte della definizione della classe.

class SearchForm(formbase.PageForm):
form_fields = form.FormFields(ISearch)
result_template = pagetemplatefile.ZopeTwoPageTemplateFile('search-results.pt')

Viene usata la classe PageForm come superclasse per ereditare le funzionalità dalla formlib stessa. Come comportamento predefinito, PageForm sa come generare tutta la porzione di HTML necessaria per la visualizzazione della form. Ma per fare ciò, formlib necessita di sapere di quali campi abbiamo bisogno. E' possibile impostare ciò utilizzando l'attributo form_field. FormField è una classe di appoggio di tipo formlib che genera i campi appropriati da un qualsiasi schema Zope 3 (in questo caso lo schema di interfaccia che è stata appena definita).

L'attributo result_template definisce una nuova pagina modello che viene usata per mostrare tutti i risultati della ricerca.

Ora viene definita una action per il form:

@form.action("search")
def action_search(self, action, data):
catalog = cmfutils.getToolByName(self.context, 'portal_catalog')

kwargs = {}
if data['text']:
kwargs['SearchableText'] = data['text']
if data['description']:
kwargs['description'] = data['description']

self.search_results = catalog(**kwargs)
self.search_results_count = len(self.search_results)
return self.result_template()

 

Questo è dove il vero lavoro prende posto. Una action formlib è generalmente un gestore che viene invocato quando si invia un form HTML. In questo caso è stata creata una nuova action chiamata search, che viene poi usata quando un utente clicca sul pulsante di ricerca. La classe basata su formlib automaticamente comprende come rendere indipendente il pulsante search dal form HTML. Il particolare gestore della action torna come risultato il result template.

 

Il Result Page Template

Al fine di mostrare i risultati della form di ricerca è necessario configurare un semplice modello di pagina. Questo modello è stato chiamato search-results.pt . La maggior parte del template non è di grande interesse, ma per gli scopi di questo tutorial viene mostrata la porzione relativa alla stampa dei risultati.

<tal:block tal:repeat="single view/search_results">
<div class="single-result">
<h4>
<span tal:replace="repeat/single/number"></span>.
<a tal:content="single/Title" tal:attributes="href single/getURL" href=""></a>
</h4>
<p tal:content="single/Description"></p>
</div>
</tal:block>

 

Siccome la precedente classe basata su formlib era una vista regolare, essa prende forma all'interno del page template. E ora è possibile assegnare semplici attributi alla vista che si possono quindi cogliere all'interno del template.

 

Collegare il Tutto Attraverso ZCML

Ora che è stata definita la classe del form e la pagina dei risultati, per andare avanti è necessario inserire il tutto all'interno di Zope. E' possibile far ciò attraverso il file configure.zcml

E' necessario, quindi, aggiungere il seguente frammento di ZCML:

<browser:page
name="search.html"
for="Products.CMFPlone.Portal.PloneSite"
class=".browser.SearchForm"
permission="zope.Public"
/>

I lettori attenti noteranno il particolare nome del tag per configurare il componente della vista, browser:page. Questo tag XML attualmente utilizza un prefisso tipico di XML che è necessario che sia definito. Normalmente questo tag è contenuto all'interno del tag configure come questo:

<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">

Controllare più volte il file configure.zcml se ci sono dubbi sulla sua configurazione.

Inoltre, poichè formlib è basato interamente sulle viste di Zope 3, viene utilizzato lo stesso metodo nella ZCML. Per chi non fosse familiare con le viste di Zope 3, questi frammenti vogliono significare che la vista search.html sarà disponibile direttamente attraverso il sito Plone, così l'indirizzo dovrebbe essere qualcosa tipo: http://localhost:8080/plonesite/search.html

Search Form

searchform.jpg

 

Search Results

 searchresults.jpg


In breve, il Primo Esempio di zope.formlib

L'esempio qui proposto mostra il più semplice form che può essere creato con formlib e come integrarlo in una semplice action. Dovrebbe essere ovvio da questo esempio come è possibile utilizzare formlib per rimpiazzare semplicemente la logica basata su CMFFormController. Di certo formlib può essere utilizzato per tante altre cose molto più avanzate come offire funzionalità di sub-form oppure form autogenerate di aggiunta e modifica per classi di tipo contenuto.

La cosa maggiormente in evidenza è che zope.formlib è pronto per essere utilizzato in Plone già da oggi. E considerato che formlib è così facile da utilizzare, consigliamo a tutti gli sviluppatori di applicazioni Plone di dargli uno sguardo.





 

FormLib e Tipi di Contenuto

FormLib e catalogazione e installazione dei Tipi

Schema Tradizionale Archetypes

Attualmente tutta la comunità Plone utilizza generalmente il framework Archetypes per sviluppare i propri tipi di contenuto. Questo framework ha introdotto il suo concetto di schema, di widget e di campi che molti sviluppatori hanno trovato soddisfacente. Il punto è che da lì a poco (forse anche in contemporanea) la comunità Zope 3 stava già sviluppando i propri costrutti degli stessi concetti. Il risultato è stato zope.interface, zope.schema e zope.app.form. Infine è arrivata zope.formlib che dovrebbe aiutare a unire tutti i precedenti in una unica interfaccia utente.

 

Zope 3 Schema

Uno schema Zope 3 funziona in modo molto simile ad uno schema di Archetypes se lo si osserva da una prospettiva concettuale. Entrambi condividono i prinicipi basilari della definizione dei campi di un tipo. Una differenza eclatante è che un campo dello schema di Zope 3 non ha una associazione diretta (all'interno dello schema stesso) con nessuna logica di interfaccia. Cioè, esso non conosce quale widget verrà utilizzato per mostrare il suo contenuto in un form web. In questo modo vengono trattati separatamente il contenuto e l'interfaccia utente. Il contenuto, dopo tutto, non dovrebbe mai aver bisogno di conoscere o preoccuparsi di ciò che avviene nell'interfaccia. Si deve preoccupare solo dei dati.

 

L'Esempio

Affinchè i concetti possano essere chiari, i precedenti codici di esempio verranno smembrati in più comuni moduli python. Questo vuol dire che bisognerà migrare l'interfaccia di ISearch dal modulo browser al nuovo modulo interfaces.

 

Uno Schema

In Zope 3 gli schema sono definiti costruendo interfacce Zope 3, molto simili a quella creata nella seconda parte di questo tutorial. Una cosa su cui non è stata fatta chiarezza è che in effetti è stato creato uno schema di rappresentazione dei campi di ricerca.

Si inizia creando una nuova interfaccia nel modulo interfaces chiamato IExampleContent. Questa interfaccia avrà vari campi e dovrebbe presentarsi più o meno così:

class IExampleContent(interface.Interface):
title = schema.TextLine(title=u'Title',
required=True)

description = schema.Text(title=u'Description',
required=False)

funny = schema.Bool(title=u'Am I Funny?',
default=False,
required=True)

really_funny = schema.Bool(title=u'Am I Really and Truly Funny?',
default=False,
required=True)

Si può dare uno sguardo al risultante modulo interfaces per osservare cosa questo file debba includere e come si debba presentare.

Come menzionato poc'anzi, l'esempio dimostra che nello schema stesso non è disponibile alcuna proprietà di interfaccia utente. Tutto ciò che è descritto riguardo lo schema e i suoi campi è ciò che è richiesto per definire il tipo di dati che esso rappresenta.


Viste Formlib

Ora che è disponibile lo schema che descrive quali tipologie di campi si hanno, è possibile usare lo stesso approccio utilizzato per costruire le viste per il contenuto.

Lo schema che è stato definito contiene una buona quantità di campi di tipo Bool. Il widget predefinito per questa tipologia di campi mostra le opzioni Vero/Falso. Per gli scopi di questo esempio, si ha la necessità di mostrare Si/No invece che Vero/Falso e si dovrà modificare un apposito widget.

def YesNoWidget(field, request, true=_('yes'), false=_('no')):
vocabulary = schemavocab.SimpleVocabulary.fromItems(((true, True),
(false, False)))
return form_browser.RadioWidget(field, vocabulary, request)

Quello che è stato creato qui è un tipo di costrutto che fornisce il widget con le caratteristiche richieste, basato su un widget esistente: il RadioWidget. RadioWidget fa riferimento ad un vocabolario che ha come voci "yes" e "no". Quindi sarà possibile definire i campi del form basati sul nuovo schema.

example_content_fields = form.FormFields(interfaces.IExampleContent)
example_content_fields['really_funny'].custom_widget = YesNoWidget

Come nell'esempio fatto nella seconda parte del tutorial, i campi del form vengono generati usando form.FormFields(). Questa classe utilizza un'interfaccia come argomento e genera i campi del form (l'associazione al campo dello schema nell'interfaccia utente) che verranno usati per le viste. La seconda riga configura il widget personalizzato.

Ora non resta che definire la vista predefinita e la form di modifica:

class ExampleContentView(formbase.DisplayForm):
form_fields = example_content_fields

def __init__(self, *args, **kwargs):
formbase.DisplayForm.__init__(self, *args, **kwargs)

# a hack to make the content tab work
self.template.getId = lambda: 'index.html'

class ExampleContentEditForm(formbase.EditForm):
form_fields = example_content_fields

def __init__(self, *args, **kwargs):
formbase.EditForm.__init__(self, *args, **kwargs)

# a hack to make the content tab work
self.template.getId = lambda: 'edit.html'

E' stata definita ExampleContentView come estensione di formbase.DisplayForm e che fa in modo che formlib possa comprendere che questa è la vista normale e così tutti i widget dovrebbero essere mostrati in modalità view. La form di modifica, ExampleContentEditForm è stata definita per estendere formbase.EditForm così che formlib sia in grado di mostrare i widget in modalità di modifica. Ma questa non è la sola cosa che formlib conosce con il form di modifica. Come impostazione predefinita, formbase.EditForm definisce una unica action apply per questo form. Quando questo form è inviato attraverso la action apply, formlib sa che deve effettivamente aggiornare l'oggetto corrente con i valori immessi. Bisogna notare che un'azione apply andata a buon fine invocherà un IObjectModifiedEvent per salvare i dati immessi.

Certamente una volta che queste viste sono state definite, necessitano di essere registrate come componente di Zope 3. Questa operazione si compie attraverso configure.zcml

<browser:page
name="index.html"
for=".interfaces.IExampleContent"
class=".browser.ExampleContentView"
permission="zope2.View"
/>

<browser:page
name="edit.html"
for=".interfaces.IExampleContent"
class=".browser.ExampleContentEditForm"
permission="cmf.ModifyPortalContent"
/>

Questo frammento di zcml mostra che la vista predefinita ha il nome index.html, mentre la form di modifica edit.html.

E' possibile dare uno sguardo al modulo browser.py e al configure.zcml per osservarne i risultati.

Tipi

Ora che lo schema e le viste sono state tutte definite per questo tipo, è tempo di costruire l'effettiva classe del tipo. Per una migliore esercitazione, si definisce questa classe nel modulo content.

class FormlibExampleContent(atapi.BaseContent):
interface.implements(interfaces.IExampleContent)

title = fieldproperty.FieldProperty(interfaces.IExampleContent['title'])
description = fieldproperty.FieldProperty(interfaces.IExampleContent['description'])
funny = fieldproperty.FieldProperty(interfaces.IExampleContent['funny'])
really_funny = fieldproperty.FieldProperty(interfaces.IExampleContent['really_funny'])

La prima riga dopo la dichiarazione della classe fa in modo che essa implementi l'interfaccia IExampleContent che è stata definita in precedenza nel modulo interfaces (uno schema è quindi un'interfaccia con i campi nel zope.schema). Le rimanenti righe configurano le proprietà python per ognuno dei campi richiesti. Per esempio, la linea funny descrive un attributo funny che è modellato dopo il campo funny dello schema in IExampleContent.

Questo assicura che la validazione di base è impostata sul tipo stesso. Se si prova a richiamare direttamente il tipo myobj con myobj.funny = 'foo' si può osservare che si solleva un'eccezione perchè 'foo' non è un valore di tipo Bool. Il tipo Bool si aspetta vero o falso.

Questo è quanto per la classe stessa. Si può osservare il modulo content.py per vederne i risultati.

Catalogazione dei Tipi

Un aspetto che è stato trascurato è che poichè non si stanno più usando i form auto-generati da Archetypes l'oggetto non può essere catalogato. Nell'universo Zope 3 queste cose dovrebbero essere compiute usando gli eventi. Poichè fomlib richiama un IObjectModifiedEvent quando avviene un salvataggio corretto, tutto ciò che è necessario fare è definire un gestore per questo evento.

def catalog_content(obj, event):
obj.reindexObject()

Il gestore stesso è estremamente semplice: esso prende come argomenti l'effettivo oggetto e l'evento (in questo caso l'istanza IObjectModifiedEvent). Sicomme si è in possesso dell'oggetto, a questo punto non resta che invocare la reindexObject().


Ovviamente è necessario aggangiarlo con l'architettura di Zope 3 e quindi bisogna andare a toccare il file configure.zcml.

<subscriber
for=".interfaces.IExampleContent
zope.app.event.interfaces.IObjectModifiedEvent"
handler=".content.catalog_content"
/>

In questo modo è possibile gestire ogni IObjectModifiedEvent che è stato invocato con un'istanza di tipo IExampleContent come oggetto. Nel caso in questione, FormlibExampleContent implementa l'interfaccia IExampleContent, quindi il gestore che è stato appena creato verrà chiamato quando l'oggetto è stato modificato.

L'ultima cosa che resta da fare è registrare il tipo con CMF/GenericSetup.


Installazione del Tipo con GenericSetup

Siccome la versione di Plone utilizzata per questo tutorial è la 2.5, è possibile utilizzare il tool GenericSetup per configurare il nuovo tipo nel sito Plone. Maggiori informazioni su GenericSetup e su Plone si possono trovare nell'eccellente tutorial di Rob Miller   Understanding and Using GenericSetup in Plone.

I passi basilari per configurare il Tipo attraverso GenericSetup sono:

  1. Creare una directory profilo con la struttura profiles/default/types all'interno della directory formlib.
  2. Costruire un nuovo file types.xml nella directory default.
  3. Creare un file chiamato FormlibExampleContent.xml nella directory types.
  4. Registrare un nuovo profilo che usa questi file attraverso GenericSetup nel file __init__.py.

L'effettiva costruzione di questi file va oltre gli scopi di questo tutoria, ma essi possono essere trovati nella directory base formlib.

 

Bisogna ricordarsi che per attivare questi Tipi in Plone 2.5 bisogna andare nel tool portal_setup, selezionare ploneexample.formlib sample content come profilo attivo del sito e quindi eseguire tutte le operazioni di importazione.

Selezionare il Profilo Attivo

selectingformlibprofile.jpg

Passi di Esportazione

exportingallsteps.jpg

Conclusioni

Lo schema Zope 3 è arrivato così in Plone. E grazie alla zope.formlib sono state auto-generato le viste e i form da usare. Il widget e le impostazioni dei campi da scegliere in Zope 3 sono minori che nel mondo Archetypes, ma in Zope 3 lo sta rapidamente raggiungendo.

Il principale pezzo mancante (dalla prospettiva della formlib) è l'utilizzo di una form di aggiunta auto-generata. Mentre è possibile svilupparli, non è facile inserirli in Plone poichè in Plone è necessario creare prima il contenuto per poi visualizzare i form.

Aggiunta di un Nuovo Oggetto ExampleContent

 addingnewinstance.jpg

Form di Modifica

contenteditform.jpg

Vista Predefinita

 contentview.jpg

 

Credits

crediti

Vincenzo Barone - Abstract