
Hi, I just started playing with Nevow yesterday, and I've got a question. I've been using PHP/Smarty for doing websites because it's pretty easy and I've been unhappy with most of the Python web frameworks I've seen (most of them have pretty ugly template syntax or are overcomplicated). However, PHP is um, not so good, so I thought I'd make the leap to Nevow which seems to satisfy my need for simplicity and not-ugliness ;) Anyway, my typical design pattern for a site is to have an index.html template with the main layout, and then include another template depending on a GET/POST variable (e.g. http://example.com?page=home). In PHP/Smarty, there is an "include" directive that will directly inject a second template: <body> { include file="$page.html" } </body> I haven't found an equivalent in Nevow, but I hacked this together (note that I am using Apache/CGI, not Twisted: index.cgi: ---------- def template(filename): """ Prepend the full path to the template directory """ return "/var/www/virtual/example.com/public_html/templates/" + filename class Index(rend.Page): """ Looks first at the "file" attribute for the fragment to include, if that isn't provided looks at the "variable" attribute for the name of the get/post variable that contains the name of the fragment to include. Failing that, just use a default fragment. """ defaultPage = 'home' docFactory = loaders.xmlfile(template("index.html")) def render_include(self, ctx, data): filename = ctx.tag.attributes.get('file') if filename is None: filename = ctx.arg(ctx.tag.attributes.get('variable')) if filename is None: filename = self.defaultPage filename = template(filename + '.html') if os.path.exists(filename): fragClass = rend.Fragment fragClass.docFactory = loaders.xmlfile(filename, ignoreDocType=True) ctx.tag.fillSlots(ctx.tag.attributes.get('slot'), fragClass()) return ctx.tag else: return "Page not found." index.html: ----------- <div id="content"> <nevow:invisible nevow:render="include" variable="page" slot="content"> <nevow:slot name="content" /> </nevow:invisible> </div> This allows me to either specify the included file by accessing a GET/POST variable: <nevow:invisible nevow:render="include" variable="page" slot="content"> or directly specify the template like: <nevow:invisible nevow:render="include" file="home" slot="content"> This all seems to work just fine. However, now I'm curious if there is a better/more direct way of achieving this. Regards, Cliff -- Cliff Wells <clifford.wells@comcast.net>

On Jun 11, 2005, at 1:37 AM, Cliff Wells wrote:
Hi,
I just started playing with Nevow yesterday, and I've got a question.
<snip> That all looks pretty good; you have more Python code than your PHP code, but that's because you check for more and it has more capability. This is the whole point of nevow; if you need to do something custom, you write some python code. And it's easy to share between pages, too. However, here are a few suggestions:
if os.path.exists(filename): fragClass = rend.Fragment fragClass.docFactory = loaders.xmlfile(filename, ignoreDocType=True)
This is weird and unnecessary. Fragment takes a docFactory argument for a reason. So, do this instead: frag = Fragment(docFactory=loaders.xmlfile(filename, ignoreDocType=True))
ctx.tag.fillSlots(ctx.tag.attributes.get('slot'), fragClass()) return ctx.tag
This is also pretty weird. I'm not understanding what the extra slot is giving you. If it were me, I would just "return frag" here and dispense with the slot in the template as well as the slot-filling.
else: return "Page not found."
index.html: ----------- <div id="content"> <nevow:invisible nevow:render="include" variable="page" slot="content"> <nevow:slot name="content" />
See comment above, I think this slot is extraneous...
</nevow:invisible> </div>
This allows me to either specify the included file by accessing a GET/POST variable:
<nevow:invisible nevow:render="include" variable="page" slot="content">
Neat!
or directly specify the template like:
<nevow:invisible nevow:render="include" file="home" slot="content">
Cool.
This all seems to work just fine. However, now I'm curious if there is a better/more direct way of achieving this.
If it works for you, it works. :-) Again, the point of Nevow is to make it really easy for you to write Python code that does what you want it to do. dp

On Mon, 2005-06-13 at 16:50 -0700, Donovan Preston wrote:
On Jun 11, 2005, at 1:37 AM, Cliff Wells wrote:
you have more Python code than your PHP code, but that's because you check for more and it has more capability.
Well, to be sure, I'd rather write 10 lines of Python than 5 lines of PHP anyway ;)
However, here are a few suggestions:
if os.path.exists(filename): fragClass = rend.Fragment fragClass.docFactory = loaders.xmlfile(filename, ignoreDocType=True)
This is weird and unnecessary. Fragment takes a docFactory argument for a reason. So, do this instead:
frag = Fragment(docFactory=loaders.xmlfile(filename, ignoreDocType=True))
Yep, found this shortly after I posted (as usual).
ctx.tag.fillSlots(ctx.tag.attributes.get('slot'), fragClass()) return ctx.tag
This is also pretty weird. I'm not understanding what the extra slot is giving you. If it were me, I would just "return frag" here and dispense with the slot in the template as well as the slot-filling.
Thanks! That made my templates quite a bit cleaner (and dropped a couple lines of Python as well). I had stumbled onto something that worked, so I hadn't bothered looking any further for the "right" solution (smacks self).
<div id="content"> <nevow:invisible nevow:render="include" variable="page" slot="content"> <nevow:slot name="content" />
See comment above, I think this slot is extraneous...
Indeed it was. Thanks a lot. Your advice was right on the money. I'm liking Nevow more by the minute =) Regards, Cliff -- Cliff Wells <clifford.wells@comcast.net>

i do it in another way: i have a BasePage class - which is a skeleton for other Pages: class BasePage(rend.Page): __implements__ = rend.Page.__implements__ TITLE = "Common Page" docFactory = loaders.xmlfile("_tpl/common/page.xml") def render_title(self, ctx, data): ctx.fillSlots("title", self.TITLE) return ctx.tag def render_content(self, ctx, data): raise NotImplementedError, "You MUST overload render_content() method!!!" And BasePage tremplate: <html> ...metas <body> ...layout <n:invisible n:render="content" /> </body> </html> And then all of the site pages are using this prototype: class Root(common.BasePage): def render_content(self, ctx, data): return loaders.xmlfile("_tpl/root.xml") i can return ANY xml-temlate i'd like :) for example a form or a "form submitted successful" message
participants (3)
-
Cliff Wells
-
Donovan Preston
-
Little