[Zope3-Users] Custom addform and object creation error
Cliff Ford
Cliff.Ford at ed.ac.uk
Wed May 4 02:50:15 EDT 2005
Hello Reuben,
I can't say anything about archetypes because I have not used Plone.
However, I can summarise some of my learning experience over the last
month. Firstly, I initially created a number of custom Edit forms, each
with a supporing class. My main requirement was to have a "Close" button
to close the form and take the user to a well-defined view. I eventually
discovered that I only needed one custom Edit form and no supporting
classes - it was all a matter of configuration.
Second, I do have one content type that needs a custom edit form. It is
a custom menu constructed from a list of lists [[],[],[]] that allows
users to add and delete items, change order, and set the link text and
tool tip. I can't remember how I started this form, but it looks as
though I replaced almost all of the content of the standard edit page
template. At the top of the form template I have this:
<html metal:use-macro="views/standard_macros/view">
<body>
<div metal:fill-slot="body">
<h3>Edit Menu: </h3>
<pre tal:content="python:view.update(context, request.form)"
tal:condition="request/form">Update Message</pre>
The last statement just calls the custom Class update method if the
request contains the form (i.e, the form has been submitted). On
reflection, I think I would now try to use more of the Zope framework -
by just replacing the widget_rows macro call (only just thought of
that!). To use the form it is declared in browser/configure.zcml:
<editform
schema="glgsite.interfaces.IGlgMenu"
for="glgsite.interfaces.IGlgMenu"
label="Edit Menu"
fields="menulist"
name="editmenu.html"
permission="zope.ManageContent"
menu="zmi_views" title="Edit"
template="menuform.pt"
class=".menuform.MenuForm" />
menulist is the list of lists. The support class (MenuForm) update
method adds, deletes and re-orders items before saving them back into
menulist. The support class also has another method to list items that
are not in the list, called like this:
<tr tal:repeat="item python:view.getAllowedSiblings(context)">
which reminds me I forgot to mention that the form iterates over the
list with this:
<tr tal:repeat="item context/menulist">
from which the sublist elements are obtained as "python:item[0]".
To call the form there needs to be a link that references the view of
the menu object. For example, if the current view is a "page" the link
looks like this: ../menu/@@editmenu.html because menu is a child of the
parent (folder) of page.
Is that enough? Reviewing my post below, I decided not to collect Dublin
Core metadata with object creation data because the extra form fields
are not passed to the createAndAdd method. Instead, I decided to
redirect to the Metadata form.
Another configuration example:
<editform
schema="zope.app.dublincore.interfaces.IZopeDublinCore"
for="glgsite.interfaces.IGlgPage"
label="Edit Page Title and Description"
name="editpagedc.html"
template="editpage.pt"
fields="title description"
permission="zope.ManageContent"
menu="zmi_views" title="Metadata"
/>
This could potentially collect all Dublin Core metadata using my custom
Edit template (with Close button) but is restricted to the title and
description fields and does not need a custom support class. It is
called with a link of the form ../menu/@@editpagedc.html (this was one
of the cases where I thought a custom form needed a custom class and
found that it did not if configured correctly).
Cliff
Reuben Christie wrote:
> Hi, cliff,
> Could you please explain me how to create custom edit form for archetype
> ? i
> guess thats what you have done when you said customAddForm
> Quoting Cliff Ford <Cliff.Ford at ed.ac.uk>:
>
>> To answer my own question, and for the benefit of anyone else who wants
>> to customise an addform:
>>
>> Even though I have a class with a createAndAdd method I found that it
>> was necessary to include the content_factory directive in the addform
>> configuration as well as the class and template directives.
>>
>> I copied the createAndAdd method from ../zope/app/form/browser/add.py
>> and added this line: self.gotoURL = str(content.__name__) after content
>> = self.add(content), having previously set gotoURL='' as a class
>> variable. I have a nextURL method:
>>
>> def nextURL(self):
>> return '../%s' % self.gotoURL
>>
>> And lo and behold on submission of the add form I get the browser view
>> of the added object. Magic!
>>
>> I am doing this customisation because I want to collect essential Dublin
>> Core data with data for the content object, rather than rely on users
>> filling in the metadata form later.
>>
>> Cliff
>>
>>
>> Cliff Ford wrote:
>>
>>> I have a custom addform that works fine with a standard
>>> configuration. However, on submission it redirects to the contents
>>> view of its container and I want it to redirect somewhere else, such
>>> as the new object's edit or metadata views. All I really need is a
>>> nextURL configuration directive, mentioned in mailings some time ago,
>>> but I don't think that has been implemented.
>>>
>>> I have created a class with a __call__ method that returns the custom
>>> form template, and a nextURL() method. In the configuration file I
>>> have replaced the content_factory directive with the class directive.
>>>
>>> With the custom form and class, the form displays and field
>>> validation still works, but with valid fields I get an object
>>> creation error:
>>>
>>> File "/usr/local/Zope3/src/zope/app/form/browser/add.py", line 71, in
>>> create
>>> return self._factory(*args, **kw)
>>> TypeError: 'NoneType' object is not callable
>>>
>>> I have looked at the add.py module and am none the wiser. I guess I
>>> have neglected to set something somewhere, may be context related.
>>> Can anyone enlighten me? The custom class has almost nothing in it
>>> (see below) so I am surprised it gets as far as it does. [I have also
>>> searched the archives and read both recent Zope3 books but can't find
>>> an answer.]
>>>
>>> Cliff
>>>
>>> Custom class:
>>>
>>> from zope.app.pagetemplate.viewpagetemplatefile import
>>> ViewPageTemplateFile
>>>
>>> class PageAddFormD:
>>> """This class reads the form data and creates a custom Page"""
>>>
>>> template = ViewPageTemplateFile('pageaddformd.pt')
>>>
>>> def __call__(self):
>>> return self.template()
>>>
>>> def getInterfaces(self):
>>> """ Don't know if I need this here """
>>> return implementedBy(GlgPage)
>>>
>>> def nextURL(self):
>>> """ return the next place to go """
>>> # have not got this far yet
>>> return '../'
>>> _______________________________________________
>>> Zope3-users mailing list
>>> Zope3-users at zope.org
>>> http://mail.zope.org/mailman/listinfo/zope3-users
>>
>> _______________________________________________
>> Zope3-users mailing list
>> Zope3-users at zope.org
>> http://mail.zope.org/mailman/listinfo/zope3-users
>>
>
>
>
>
>
> _______________________________________________
> Zope3-users mailing list
> Zope3-users at zope.org
> http://mail.zope.org/mailman/listinfo/zope3-users
More information about the Zope3-users
mailing list