conditional {{include}} in view

1,037 views
Skip to first unread message

Kernc

unread,
Jul 8, 2011, 2:07:16 AM7/8/11
to web2py-users
Ok, so this is my setup:

I have article() function inside default controller, which obtains
article title in request.args, puts ('articles/'+str(request.args[0])
+'.html') into returned dict(article=...), and serves appropriate
article's HTML from article.html with

<!-- various common tags along with <body> above and </html> below...
-->
<article>
{{include article}}<!-- includes the right article/with-some-
title.html -->
</article>
<!-- ... -->

For example, if I access http://domain/article/with-some-title, it
renders views/articles/with-some-title.html.
I like that. :-)

But then I have /about URL, which calls about() function inside
default controller, but which I would like to use the same article
template from article.html, i.e. to follow DRY.

So I have tried to put my content in about.html in a variable
{{article_content = MARKMIN('About us...')}} and then {{include}}
modified article.html

<article>
{{if article_content:}}{{=article_content}}{{pass}}{{else}}{{include
article}}{{pass}}
</article>

(Besides {{if article_content:}} I tried with try-except too. Neither
worked.)
When accessing /about, the ticket told me the error was in undefined
'article' variable in the include expression.

So I tried it another way, by defining block with default content in
article.html

{{block article_content}}{{include article}}{{end}}

and extending article.html in about.html

{{extend 'article.html'}}{{block article_content}}{{=MARKMIN('About
us...')}}{{end}}

As per documentation, default value inside {{block}} (in my case
'{{include article}}') should be replaced with specified value (in
my case {{=MARKMIN(...)}}). But again, the ticket reports the same
error:

...
File "/home/****/web2py/gluon/template.py", line 449, in include
text = self._get_file_text(filename)
File "/home/****/web2py/gluon/template.py", line 430, in
_get_file_text
filename = eval(filename, self.context)
File "<string>", line 1, in <module>
NameError: name 'article' is not defined

To avoid using {{include}}, the next thing I am about to try is:

{{block article_contents}}{{if article:}}{{=open(article).read()}}
{{pass}}{{end}}

but this way I have to maintain os.getcwd() and annote the article
with proper path to my views. I don't know how stable this is.

Inexperienced as I am, I'm assuming it's possible I'm doing something
horribly wrong. What is that? :-)

TL;DR: The templating system counter-intuitively gives unconditional
priority to {{include}} expressions, which it evaluates first.

Oh, and if you can please tell me how I can make the about() function
to use the article.html view instead of default about.html view, that
would solve my DRY problem as well, I suppose. :-)

Thanks!

Anthony

unread,
Jul 8, 2011, 10:26:08 AM7/8/11
to web...@googlegroups.com
First, if you want to use a particular view, you can always explicitly assign response.view:
 
def about():
    response.view='default/article.html' # This view will be used instead of 'default/about.html'.
    # more code
    return dict(...)
 
Also, note that the {{include}} statement is not a Python statement -- it is processed by the template engine before everything is converted to Python. So, if you have an {{include 'someview.html'}} inside an if statement, the 'someview.html' template will still be included in the assembled Python code, though it will only be executed conditionally (based on the condition of the if statement). Also, because of this, although you may use variables in your {{include}} statements, as you have, usage of variables prevents bytecode compiling of the views. The reason is that the included views have to be determined at compile time, but the value of the variables is not known until run time.
 
In the places where you are getting the error about 'article' not being defined, I assume your controller action is not actually returning a variable called 'article' to the view. If you need to conditionally test whether a particular variable is available in a view, you can do {{if 'article' in response._vars:}} or {{if 'article' in globals():}}.
 
Anthony

Kernc

unread,
Jul 8, 2011, 12:14:48 PM7/8/11
to web...@googlegroups.com
OMG, setting response.view does it for me 110%!
Confident in the ease of use of web2py, I swear I tried this the very first. Maybe I mistyped it to response.view = 'article.html' or request.view, and then just turned to alternatives. Anyway, now it works! :-D

I also understand your explanation, except one thing: if I have an {{include}} inside a {{block}} as a default value (both these statements are template, non-python statements), and that default is overridden, and since {{block}} somewhat introduces conditioning, the inner {{include}} statement need-not be expanded, so {{block some}}{{include article}}{{end}}, with some block overridden, shouldn't throw error on article variable not set. I think.

Anyway, taking note of your comment regarding not compiled views, I now see I am doing the whole thing wrong, so I'm switching to {{extends}} and {{blocks}} instead (no more need for variable includes). response.view saves the day! :-)

Thank you and KUGW!

Anthony

unread,
Jul 8, 2011, 12:36:52 PM7/8/11
to web...@googlegroups.com, kern...@gmail.com
On Friday, July 8, 2011 12:14:48 PM UTC-4, Kernc wrote:
I also understand your explanation, except one thing: if I have an {{include}} inside a {{block}} as a default value (both these statements are template, non-python statements), and that default is overridden, and since {{block}} somewhat introduces conditioning, the inner {{include}} statement need-not be expanded, so {{block some}}{{include article}}{{end}}, with some block overridden, shouldn't throw error on article variable not set. I think.
 
Yes, that's a good point -- I'm not sure exactly how blocks work on the back end, but apparently it does read that include statement before replacing the block content.
 
Anthony

Michael Dunga

unread,
May 2, 2018, 5:02:38 PM5/2/18
to web2py-users
wow, just what I wasl ooking for

Gilad Hoshmand

unread,
Jun 4, 2019, 4:29:10 AM6/4/19
to web2py-users
For those who arrive late, from the docs:
{{if some_condition:}}
{{include 'this_view.html'}}
{{else:}}
{{include 'that_view.html'}}
{{pass}}
Reply all
Reply to author
Forward
0 new messages