[Zope] Problem when trying to use metal macros from another page
template
Josef Meile
jmeile at hotmail.com
Wed Nov 5 08:18:32 EST 2003
Hi,
in the past I had some security issues because
I was using a bad way to add dinamically attributes
to my Page Templates (thanks to Chris Withers to
point it out and to Dieter for the solution). I was doing:
manage_addJMBoringForm=PageTemplateFile('zpt/JMBoring_Add',globals())
manage_addJMBoringForm.Kind='JMBoring'
then I replaced it for:
_addJMBoringForm=PageTemplateFile('zpt/JMBoring_Add',globals())
def manage_addJMBoringForm(self):
return _addJMBoringForm.__of__(self)(Kind='JMBoring')
Now the issue that I'm having is that the later approach
doesn't work when the attribute that I want to store in the
"options" built-in variable is a Page Template with macros.
I have the following structure:
Base Class JMZPTMacros:
<ZopeHome>/lib/python/Shared/JMUtils/JMZPTMacros.py
<ZopeHome>/lib/python/Shared/JMUtils/zpt:
Here I have the following Page Templates with some macros
that I use from my other product JMBoring:
generic.zpt
generic_add.zpt
generic_edit.zpt
generic_view.zpt
Product JMBoring, which subclases from JMZPTMacros:
<ZopeHome>/lib/python/Products/JMBoring/JMBoring.py
<ZopeHome>/lib/python/Products/JMBoring/zpt
Here I have some Page Templates that use the macros
defined on the JMZPTMacros product:
index_html.zpt
JMBoring_Add.zpt
JMBoring_Edit.zpt
JMBoring_View.zpt
What I'm trying to do is to call some macros from "generic.zpt"
and "generic_add.zpt" in "JMBoring_Add.zpt". The main problem
is that the "JMBoring_Add.zpt" Template is loaded outside of
the JMBoring class definition (constructor methods are declared
before the classe definition), while the other Templates like:
"manage_view", "index_html", and "manage_main" are inside, so,
they can access the macros in the "JMZPTMacros" base class
just by typing:
<p metal:use-macro="here/TemplateID/macros/MacroID">Execute macro</p>
but in the JMBoring_Add.zpt, an AttributeError exception is
raised. I guess it's because the other Templates are called from
an instance of JMBoring, so, they have access to the methods
of the base class JMZPTMacros, while when calling this
template, an instance of such class still doesn't exist, for this
is a contructor method.
That's how I did it (It has the security assertions that Chris
mentioned before):
file <ZopeHome>/lib/python/Shared/JMUtils/JMZPTMacros.py:
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
class JMZPTMacros:
generic_add=PageTemplateFile('zpt/generic_add',globals())
generic_add._owner=None
generic_edit=PageTemplateFile('zpt/generic_edit',globals())
generic_edit._owner=None
generic_view=PageTemplateFile('zpt/generic_view',globals())
generic_view._owner=None
generic=PageTemplateFile('zpt/generic',globals())
generic._owner=None
file <ZopeHome>/lib/python/Products/JMBoring/JMBoring.py:
################################################
Here comes some imports and variable definitions that one
has to do to give the class the basic characteristics of a zope
product.
They weren't included on this message.
################################################
_addJMBoringForm=PageTemplateFile('zpt/JMBoring_Add',globals())
def manage_addJMBoringForm(self):
"""Here some attributes are added to the template"""
#The following two lines should be replaced with a safer
#implementation
_addJMBoringForm.generic=JMZPTMacros.generic
_addJMBoringForm.generic_add=JMZPTMacros.generic_add
_addJMBoringForm._owner=None
return _addJMBoringForm.__of__(self)(Kind='JMBoring')
def
manage_addJMBoring(self,id,title='',description='',REQUEST=None,submit=None)
:
"""Invoques the __init__ method of the JMBoring class"""
id=id.replace(' ','_')
boringObj=JMBoring(id,title,description)
self._setObject(id,boringObj)
if REQUEST is not None:
try:
destURL=self.DestinationURL()
except:
destURL=REQUEST['URL1']
if submit==" Add and Edit ":
destURL="%s/%s" % (destURL,quote(id))
REQUEST.RESPONSE.redirect(destURL+'/manage_main')
return ''
class JMBoring(SimpleItem, PropertyManager, JMZPTMacros):
"""JMBoring class definition"""
################################################
Here comes all the stuff necessary to make my class work
as a zope product (__init__ method, security declarations,
properties, etc.).
It wasn't included on this message
################################################
manage_main=PageTemplateFile('zpt/JMBoring_Edit',globals())
manage_main._owner=None
################################################
More stuff comes here
################################################
manage_view=PageTemplateFile('zpt/JMBoring_View',globals())
manage_view._owner=None
index_html=PageTemplateFile('zpt/index_html',globals())
index_html._owner=None
InitializeClass(JMBoring)
Then I called the macros in JMBoring_Add.zpt:
<p metal:use-macro="template/generic_add/macros/addHeader">Add Header</p>
<p class="form-help">
Optional fields are written in <b><i>italic</i></b>
</p>
<span metal:use-macro="template/generic_add/macros/addForm">
<span metal:fill-slot="moreProps" tal:omit-tag="">
<tr>
<td align="left" valign="top">
<div class="form-optional">description</div>
</td>
<td align="left" valign="top">
<textarea name="description" rows="6" cols="35"></textarea>
</td>
</tr>
</span>
</span>
<p metal:use-macro="template/generic/macros/genericFooter">Generic
Footer</p>
This works, but as mentioned before, it's not safe. Then I tried the
following without any success:
def manage_addJMBoringForm(self):
"""Here some attributes are added to the template"""
#I only replaced the line where the generic
#Template was included. This line uses the unsafe
#sintax
_addJMBoringForm.generic_add=JMZPTMacros.generic_add
_addJMBoringForm._owner=None
#Here I included the generic Template as an attribute of the options
#built-in variable
return
_addJMBoringForm.__of__(self)(Kind='JMBoring',generic=JMZPTMacros.generic)
Then I called it:
<p metal:use-macro="options/generic/macros/genericFooter">Generic Footer</p>
I got the following traceback:
Traceback (innermost last):
Module ZPublisher.Publish, line 98, in publish
Module ZPublisher.mapply, line 88, in mapply
Module ZPublisher.Publish, line 39, in call_object
Module Products.JMBoring.JMBoring, line 70, in manage_addJMBoringForm
Module Shared.DC.Scripts.Bindings, line 252, in __call__
Module Shared.DC.Scripts.Bindings, line 283, in _bindAndExec
Module Products.PageTemplates.PageTemplateFile, line 96, in _exec
Module Products.PageTemplates.PageTemplate, line 95, in pt_render
- <PageTemplateFile at />
Module TAL.TALInterpreter, line 200, in __call__
Module TAL.TALInterpreter, line 244, in interpret
Module TAL.TALInterpreter, line 689, in do_useMacro
Module Products.PageTemplates.TALES, line 220, in evaluate
- URL: JMBoring_Add
- Line 17, Column 0
- Expression: standard:'options/generic/macros/genericFooter'
- Names:
{'container': <__FactoryDispatcher__ instance at 015C0980>,
'default': <Products.PageTemplates.TALES.Default instance at
00A85474>,
'here': <__FactoryDispatcher__ instance at 015C0980>,
'loop': <SafeMapping instance at 015EFFF0>,
'modules': <Products.PageTemplates.ZRPythonExpr._SecureModuleImporter
instance at 00A85A34>,
'nothing': None,
'options': {'Kind': 'JMBoring',
'args': (),
'generic': <PageTemplateFile at 0xa69970>},
'repeat': <SafeMapping instance at 015EFFF0>,
'request': <HTTPRequest,
URL=http://localhost:8080/manage_addProduct/JMBoring/manage_addJMBoringForm>
,
'root': <Application instance at 015ABE18>,
'template': <PageTemplateFile at />,
'traverse_subpath': [],
'user': admin}
Module Products.PageTemplates.Expressions, line 206, in __call__
Module Products.PageTemplates.Expressions, line 194, in _eval
Module Products.PageTemplates.Expressions, line 150, in _eval
- __traceback_info__: options
Module Products.PageTemplates.Expressions, line 371, in restrictedTraverse
- __traceback_info__: {'path': ['generic', 'macros', 'genericFooter'],
'TraversalRequestNameStack': ['genericFooter', 'macros']}
TypeError: 'in' or 'not in' needs sequence right argument
Same when I only use:
<p tal:define="generic options/generic"></p>
or
<p tal:define="generic python:options['generic']"></p>
So, I did:
<p tal:replace="options"></p>
and I got:
{'args': (), 'Kind': 'JMBoring', 'generic': <PageTemplateFile at 0xa69970>}
Wich means that my template is in the options variable,
but for some reason the macros stored there can't be
used. Does somebody know how I can solve the problem?
or perhaps an alternative way of solving it?
Thanks in advanced,
Josef
More information about the Zope
mailing list