[Twisted-web] Re: Nevow and template like files

Valentino Volonghi aka Dialtone dialtone at divmod.com
Wed Sep 6 18:45:58 CDT 2006


On Wed, 06 Sep 2006 11:03:28 +0300, Nuutti Kotivuori <naked at iki.fi> wrote:
>Valentino Volonghi aka Dialtone wrote:
>Okay, consider the content page shown above. Now let's assume that
>most pages don't need the "head" pattern at all. I wouldn't want to
>write the empty pattern on all pages just because it has to be there,
>instead I would just want to say that put T.invisible() there if the
>pattern doesn't exist. (With just the "head" pattern it wouldn't be so
>much of a problem, but I might later on have to add some more, and I
>don't want to change every content page just because one content page
>requires something special.)

>So this is what I'd like the default for. But ofcourse, if I load the
>entire page first, and then just use the inevow.IQ machinery, making
>the default patterns is easy.

Another solution is to write your own loader by implementing inevow.IDocFactory and the using loaders.xmlfile internally so that you can catch exceptions and do what you want with the behavior. This also sounds reasonable a reasonably easy.

>> loaded = loaders.xmlfile('file')
>> some_pattern = inevow.IQ(loaded).onePattern('whatever')
>
>That seems to work at first - but if there are any macros or render
>methods inside the file I load, then I get Could not adapt error to
>IMacroFactory.

Uhmmm... Indeed the problem of the macro factory is not of secondary importance. Basically it doesn't make sense to call load() without a MacroFactory. This can be solved by building your own WovenContext before passing it to the loader.

>> Don't pass the context, what's the problem here?
>
>Macros and render methods. In the case of the snippet pages, I would
>like them to be interpreted in the context of the Fragment class that
>is loading the entire snippet page.

That is done by default if you pass the context you are given by any of the methods in the Fragment.

>I understand that the macro is not reloaded - but each macro will load
>the page once. Which would be a problem on a page with hundreds of
>snippets if every snippet would cause the page to be loaded once.

It's still a one time cost.

>Okay, I will try to be a bit clearer. For now, I have two problems -
>how to load the "content" page all at once and then use patterns with
>optional defaults from it. And then the snippet problem. I will
>outline the snippet problem later.
>
>I wrote a really tiny testsite outlining my problem. I will put the
>three files here:
>
>,----[ testpage.xhtml ]
>| <?xml version="1.0"?>
>| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
>| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
>| <html xmlns="http://www.w3.org/1999/xhtml"
>|   xmlns:n="http://nevow.com/ns/nevow/0.1">
>|   <head>
>|     <title>
>|       <n:invisible n:macro="title">Page Title</n:invisible>
>|     </title>
>|     <n:invisible n:macro="head" />
>|   </head>
>|
>|   <body>
>|     <h1><n:invisible n:macro="title">Page Title</n:invisible></h1>
>|
>|     <div class="plain-content">
>|       <n:invisible n:macro="content" />
>|     </div>
>|   </body>
>| </html>
>`----
>
>,----[ datapage.xhtml ]
>| <?xml version="1.0"?>
>| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
>| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
>| <html xmlns="http://www.w3.org/1999/xhtml"
>|   xmlns:n="http://nevow.com/ns/nevow/0.1">
>|   <head>
>|     <title><n:invisible n:pattern="title">Data Page</n:invisible></title>
>|     <n:invisible n:pattern="head" />
>|   </head>
>|   <body>
>|     <n:invisible n:pattern="content">
>|       <p>
>|       <n:invisible n:macro="test">
>|           Replaced by test data.
>|         </n:invisible>
>|       </p>
>|     </n:invisible>
>|   </body>
>| </html>
>`----
>
>,----
>| from nevow import inevow, loaders, rend, guard, url, stan, tags as T
>|
>| class TestPage(rend.Page):
>|     docFactory = loaders.xmlfile('testpage.xhtml')
>|     datapage = None
>|
>|     def macro_title(self, ctx):
>|         return loaders.xmlfile(self.datapage, pattern='title')
>|
>|     def macro_head(self, ctx):
>|         return loaders.xmlfile(self.datapage, pattern='head')
>|
>|     def macro_content(self, ctx):
>|         return loaders.xmlfile(self.datapage, pattern='content')
>|
>| class DataPage(TestPage):
>|     datapage = 'datapage.xhtml'
>|
>|     def macro_test(self, ctx):
>|         return 'Test successful.'
>`----

I'd rewrite the example in the following way:

class TestPage(rend.Page):
    docFactory = loaders.xmlfile('testpage.xhtml')
    patternGenerator = None

    def macro_title(self, ctx):
        return inevow.IQ(self.patternGenerator).onePattern('title')

    def macro_head(self, ctx):
        return inevow.IQ(self.patternGenerator).onePattern('head')

    def macro_content(self, ctx):
        return inevow.IQ(self.patternGenerator).onePattern('content')

class DataPage(TestPage):
    patternGenerator = loaders.xmlfile('datapage.xhtml')

    def macro_test(self, ctx):
        return 'Test successful.'


>Now, how would I modify this example so that "datapage.xhtml" is
>loaded only once, even though there are three different macros using
>it. And also so that the "head" pattern could be optional and is
>replaced by T.invisible() if not present. All the while not breaking
>the macro_test part, splitting the pages into several files or
>breaking the normal html rendability/editability of the datapage.

I think the solution above should work without any problems, except I'm not sure that macro_test could actually work at all in nevow currently, but it may work.

In case you want to avoid to call loaders.xmlfile('datapage.html') each time you might try a simple metaclass solution that grabs patternGenerator attribute before building the class and changes it to be an instance of loaders.xmlfile.

>I will come up with something outlining the snippet problem later.

ok.



More information about the Twisted-web mailing list