Hi everybody, Here is the new ad-hoc FAQ. I'll start versioning it as of now; this is version 0.1. How we'll do the actual versioning we'll still have to decide on, but at least we have a way to refer to this one now. Regards, Martijn ---- Note on the use of the Zope mailing lists: The Zope Documentation Project is getting its own mailing list (zdp@zope.org). In an attempt to gain publicity and support among the Zope community, I'll post this development FAQ to the main Zope list as well, however. Feel free to respond to it on either list for now, but you are encouraged to join the ZDP mailing list and to send new FAQ suggestions there. You can subscribe to the ZDP mailing list by using the page: http://www.zope.org/mailman/listinfo/zdp Note on the categorizing of this FAQ: This FAQ is a FAQ in progress. It is uncompletely unstructured, unrelated questions are mixed haphazardly. If you feel the calling to categorize the FAQ or to maintain the questions for a particular topic, feel free to mail your changes to the list, and thanks in advance! Note on the code examples and StructuredText: I've reconsidered and used normal '<' and '>' characters in sample DTML, for the reason that at least the FAQ is readable as text then. If you try to feed this FAQ through:: <!--#var faq.stx fmt="structured-text"--> there will be an error message in Zope, however. For some reason Zope seems to try to interprete even StructuredText that uses & escape codes. Until this issue is resolved it is not possible to render this document into HTML. In my uninformed opinion, StructuredText code examples shouldn't be interpreted by Zope as actual DTML. There may be some rather subtle technical difficulties involved however. Any input on this is very welcome. Until the matter is resolved, the FAQ document will use StructuredText in the plaintext readable way. Thanks to Martijn Pieters in being so considerate to supply HTML escaped DTML examples; it's unfortunate his efforts weren't useful this time. Note on my availability: Martijn Faassen (me!), ad-hoc FAQ maintainer of the ZDP's Zope FAQ is generally not available to read or respond to email on friday, saturday and sunday. It is suggested ZDP related communication goes through the ZDP mailing list at zdp@zope.org anyway, and is not sent directly Martijn. This way anyone who wants to do something for the ZDP (such as editing and extending the FAQ) does not have to wait for Martijn to read his mail, having all relevant information available on the list. * How do I return an image from an External Method? Example (for a png image):: def foo(self, RESPONSE): # set the header RESPONSE['content-type'] = 'image/png' # return the actual image data return mkimage() Another way to set the header information is:: RESPONSE.setHeader('content-type','image/png') * How can an External Method refer to the objects in the Zope app? Use an External Method that gets passed 'self'. 'self' is your hook into Zope world. From 'self' you should be able to get anywhere you'd like to go. 'self' is the folder in which the external method is called. External Methods are methods of Folders. Since External Methods are acquired, self is not always the same Folder in which the method is defined--it may be a child Folder. * Is there any way for External Methods to access files on the filesystem of the server? An External Method can access anything on the server computer that the Zope process has access to. Therefore, an External Method can do just about anything a Python program can do. This is both a power and a liability. * Can I restrict what an External Method can do? Is there somekind of sandbox environment for External Methods? Right now there is no sandbox execution environment for External Methods. An External Method has access to everything that the Zope process has access to. This is one of the reasons why External Methods are required to be defined in the Extensions directory--it's easier to keep an eye on them there. * How do I call an external method from DTML? Use:: <!--#var "external_method_name(arguments)"--> to call any External Method in the folder (or acquired by the folder). The more explicit alternative is:: <!--#var expr="external_method_name(arguments)"--> The rule is that anything between double quotes in the first argument of the #var tag is interpreted as an expression attribute; a first argument without quotes is interpreted as a name attribute. * Why does StructuredText have trouble rendering the '#var' tags in the FAQ? Why do you use the HTML & escape codes in the FAQ when they don't work well either? I suspect there is some interaction between StructuredText and DTML that causes '#var' tags to be interpreted even when in a StructuredText code block (indicated by '::' or single quotes). I don't know any workaround right now, so I leave in ugly escape codes to encourage suggestions. :) * In a DTML expression, how do I access variable names with a '-' in them? (such as 'sequence-item') Any variable name (including those with '-') can be accessed in the '_' namespace. This contains a dictionary of all variables in the default namespace. To access 'sequence-item' you therefore use:: _['sequence-item'] * How do you safely do a backup of the Zope database? ('data.bbb' in the 'var' directory) In Zope 1.10 and later, you can simply back up the data.bbb. Because of the way the file written (all write operations are appends), it is highly unlikely for a backup file created directly to have a problem. If the database is being written while the file is being copied, then the Zope may discard the last transaction when reading the copy, if the last record is incomplete. Alternatively, you could export the entire site and backup the export file. This won't be a full backup however, as it won't contain old revisions of objects. Yet another alternative is to (mis)use the Pack operation (in the Zope Control Panel, database management). Pack will create a Data.bbb.old backup copy of your file before packing (for safety), which you could then back up. To exploit this side effect you could do a pack that says something ridiculous (like pack anything older than thousand days). * How do I pass a non-form variable to the next requested URL? Use Hidden fields within the form:: <input type="hidden" name="varname" value="<!--#var varname-->"> * How do I define a variable for use in a document Set it in REQUEST:: <!--#call "REQUEST.set('varname', value)"--> * How do I tell the tree tag to show only Folders? By using the objectValues function in the branches_expr attribute of the tree tag. The objectValues function of a folder returns all objects contained by that folder. You can however, specify a list of object metatypes that it should return. objectValues(['DTML Document']) will only return all DTML Document objects in a Folder. Other metatypes you could select on are: Folder, DTML Method, File, Image, Mail Host, User Folder and Session. This is not a complete list, as Products can and will define their own metatypes. If you want to show more types, just add them to the list, like objValues(['Image', 'File']). Example of a Folder tree (with links to them):: <!--#tree branches_expr="objectValues(['Folder'])"--> <A HREF="<!--#var URL1-->/<!--#var id-->"> <!--#var title_or_id--> </A> <!--#/tree--> * How can I collapse or expand a tree using a URL? The tree tag will show a tree fully expanded when the 'expand_all' variable is present in its namespace. So when a URL, showing a tree, is called with ?expand_all=1, the tree tag will expand all it's branches. Collapsing can be achieved with collapse_all. The following example shows a tree with collapse and expand 'buttons':: <A HREF="<!--#var URL0-->?expand_all=1"> Expand all</A>| <A HREF="<!--#var URL0-->?collapse_all=1"> Collapse all</A> <!--#tree--><!--#var id--><!--#/tree--> * How can I limit a tree to showing only *one* branch at a time? Use the 'single' attribute for your tree, like in:: <!--#tree single--><!--#var id--><!--#/tree--> * What is the difference between a DTML Method and a DTML Document? A DTML Method is what used to be just a Document in pre 1.10 releases. DTML Methods are not objects, they are methods. If you have a folder called 'foo', and it contained a DTML Method called 'bar', then 'bar' is a method of 'foo'. 'foo' doesn't contain the object 'bar', it has the method 'bar' bound to it. What this means is that from 'bar''s point of view, 'self' is a Folder object, and any properties it sees are properties of 'foo', not itself. DTML Documents are Zope Objects. Their idea of 'self' is themselves. They are contained in folders, but are not methods bound to that folder, they are instances of 'DTMLDocument.DTMLDocument'. They can manage their own Properties (because they inherit 'PropertyManager.PropertyManager'). Both DTML Documents and DTML Methods can hold DTML and content. The difference is subtle. DTML Methods would be used when the answer to the question "Am I showing some other objects content through me?" is Yes. DTML Documents should be used when the answer to the question "Am I the content I want to display?" is Yes. DTML Methods have the advantage that they don't have any properties, and their perspective of aquisition is from their containing folders point of view. DTML Documents have properties which may interfere with aquisition you'd want to do, and aquisition is from their own point of view, which may not be what you want. * How can I show all form data/cookies/REQUEST vars without knowing their names? By using the #in tag, you can easily all show all data in any dictionary object, like REQUEST.form, REQUEST.cookies and even REQUEST itself. Just call the items() method of the dictionary, and the #in tag will provide a sequence-key and sequence-item variable for every item in the dictionary. Show showing all form data can be done like this:: <!--#in "REQUEST.form.items()" sort--> <!--#var sequence-key-->: <!--#var sequence-item--><BR> <!--#/in--> Use REQUEST.cookies.items() for all your cookies, and REQUEST.items() for all REQUEST variables, including CGI Environment variables. * What is a Principia Draft? It is a special use of the session object, but it appears to be partially broken. When you create a Principia Draft, it asks you to specify an orginal object, from the same Folder you are creating the Draft in. This will be your 'draft', on which you can make changes invisible to the outside world. The draft contains an invisible Session object that is immediatly started and joined, and an invisible UserFolder to facilitate extra users (for example, customers that want to be able to view your work on it as well, but have no access to it otherwise). The Principia Draft suffers two problems however. The first is really a Session object bug, in that security for Session objects is broken. The second problem is that the Userfolder and Session controls are inaccessible via the management screens. The latter problem is caused by convention changes in the Folder object (or the ObjectManager class really, used by Folder). I think that Folder objects *used* to call 'title_and_id' on a object when displaying it in it's management screen, but the current release of Zope constructs the id and title of an object by using its id and title separately. Principia Drafts made use of the call to 'title_and_id' to insert links to its UserFolder and Session controls. As this now doesn't happen anymore, you will have to do this yourself. As long as you have access to Session objects, you can change users on a Principia Draft object by calling it's 'users__draft__.manage_main' method, and reach the Session controls by calling its 'manage_approve__draft__' method. The URLS are:: http://yoursever.com/Zope/Draft/users__draft__/manage_main and:: http://yoursever.com/Zope/Draft/manage_approve__draft__