quick search:
 

Simple Templating System

Submitted by: runyaga
Last Edited: 2001-07-27

Category: Python(Script)

Average rating is: 3.5 out of 5 (2 ratings)

Description:
I wanted to create a easy-to-use extensible framework for people to add 'paragraphs' to a DTML Document without having to code HTML. The idea is borrowed from Interwoven and how they 'fill data' into templates. In ZOPE we can easily create our own templates with a little Python, DTML and ZOPE know-how we can do it in under a 80 lines. Best part -- no SQL ;)

This demonstrates namespaces and Python wrapping the ZOPE API for propertysheets. Its a in-depth script that aims to provide some explanation of how ZOPE is done. It requires 4 files to be put into the root of your folder where you are creating your DTML Documents.

the only DTML Document, MyContentObject should (doesnt need) have a text property assigned to it called para_1 and you should fill in some random text into the value input box.

Please NOTE: my core Python Script is very ugly. I will refactor it later. I just wanted to be celebrate the 100th recipe on zopelabs ;)


Source (Text):
#create a Folder called MiniCMS and do teh following inside that folder!

############
#create a DTML Document, MyContentObject
#title it My Content Object
<dtml-var standard_html_header>
<h2><dtml-var title_or_id></h2>
<dtml-in "getParagraphs(this())">
<p>  </p>
</dtml-in>
<dtml-var standard_html_footer>

##############
#create a DTML Template, editTemplate
<dtml-var standard_html_header>

<dtml-in getParagraphs>
<p>  </p> <a href="&dtml-URL1;/shiftPropertyOrdering?propSequenceNumber=&dtml-sequence-index;">Delete Paragraph</a>
</dtml-in>
<br>
<form method="POST" action="&dtml-URL1;/addPropertyToDocument">
<input type="hidden" name="type" value="text"
<input type="hidden" name="id" value="para_<dtml-var "_.len(getParagraphs())+1">">
<textarea name="value" cols="30" rows="7"></textarea> <br />
<input type="submit" name="submit" value="Create Paragraph">
</form>
<dtml-var standard_html_footer>

###############
#create a Script (Python), addPropertyToDocument
#it has a Parameter List: self=None
r = context.REQUEST
#we do this because sending a REQUEST returns us back to manage_
context.manage_addProperty(r['id'], r['value'], r['type'])
return r.RESPONSE.redirect(r.URL1+'/editTemplate')

############
#create a Script (Python), getParagraphs
#assumes obj has paragraph properties starting with para_
#propertyValues return tuple (id, value)

paragraphs=[]
prefix='para_'

#DTML Methods acquire namespace/context, so we dont have to explicit pass in obj
if self==None:
    self=context

for id,val in self.propertyItems():
    if id[:len(prefix)]==prefix:
    paragraphs.append(val)

return paragraphs

##############
#create a Script (Python), shiftPropertyOrdering
#it has a Parameter List: self=None, propSequenceNumber=None
req=context.REQUEST
prfx='para_'
del_no=int(propSequenceNumber)

if self==None:
    self=context

#sanity check
if del_no==None:
    raise Exception, "sequence number out of range"

hash = {}
for id, val in self.propertyItems():
    if id[:5]==prfx and int(id[5:])>=del_no:
        no = int(id[5:])
        hash[no]=val

pnums = []
pnums = hash.keys()
pnums.sort()

for x in pnums:
    if x+1 in hash.keys():
        hash[x]=hash[x+1]
    else: #we've gotten to the last element and we can remove it
        hash[x]=''  #not needed

#we change the newly allocated properties
self.manage_changeProperties(hash)

#we delete the last property
ids_to_remove=(prfx+str(pnums[-1]),) #sequence of ids to delete
self.manage_delProperties(ids_to_remove)

#redirect back to DTMLDocument/editTemplate
return req.RESPONSE.redirect(req.URL1+'/editTemplate')

Explanation:
basically you create a DTML Document, which is in control of how its laid out. you then edit the Paragraphs/Properties by calling a DTML Method, editTemplate on it like, dtmlDocument/editTemplate you will notice, in the DTML Document I pass the Script, getParagraphs() a variable called this() which is the DTML Documents namespace, if I do not pass in a value for self in the Method it will assume its a DTML Method and set self=context. This is important because a DTML Method acquires its namespace of the object its called on, so context (when a DTML Method is called) IS the DTML Document, MyContentObject.

The editTemplate method just blurts out all of the properties that begin with 'para_' and uses a textarea and a html form to allow you to add a new paragraph, which calls the addPropertyToDocument wrapper around manage_addProperty and then redirect back to the Method being called on the DTMLDocument.

Now the tricky part, if we DELETE a Paragraph/property we call shiftPropertyOrdering and tell it what number 'para_' (starting from 0) we deleted. we then order them into a list, iterate over the one we changed and 'higher' by filling in new values for them. each para_x gets para_x+1's values. Then we submit the changes and then delete the top 'para_' property since its now located at the original len(propertyItems)-1.

I really hope this points out explicitly how to handle the DTML Namespace and shows how a few methods can go a very long way.


Comments:

has a minor bug ;( by runyaga - 2001-07-25
i didnt test it well enough and found a bug.  its inside the shiftPropertyOrdering... if you can figure it out please reply ;)  I will figure it out later.  its **not** a show stopper.  the recipe is still useable.
 
Re: has a minor bug ;( by polaris - 2001-07-25
i did not test this code below as-is, but it looks to me like you need to add the prefix from earlier to each key of the hash so that manage_changeProperties will work correctly.

for x in pnums:
    if x+1 in hash.keys():
        hash[x]=hash[x+1]
    else: #we've gotten to the last element and we can remove it
        hash[x]=''  #not needed

#we change the newly allocated properties
self.manage_changeProperties(hash)

i rewrote it and added these lines:

for x in pnums:
    if x + 1 in hash.keys():
        hash[x] = hash[x + 1]
    else:
        hash[x] = ''

hashish = {}
for key in hash.keys():
    hashish[prefix + str(key)] = hash[key]

self.manage_changeProperties(hashish)

probably there is a better way, but..... :)



syntax error? by rcam - 2001-07-27
Hi,
I'm getting the following error when creating the getParagraphs script..

File "", line 15

    paragraphs.append(val)

             ^

SyntaxError: invalid syntax

Any help would be appreciated...
Thanks
Bob