bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.43k stars 1.46k forks source link

rebasing to templates defined as a string. #521

Open allanderek opened 11 years ago

allanderek commented 11 years ago

Currently one can do:

welcome_template = """<h1> Welcome</h1>"
...
return bottle.template(welcome_template, ...)

and all works fine. However it would be nice to be able to do:

root_template = """<html><head></head><body>
%include
</body></html>"""

welcome_template """<h1> Welcome </h1>
%rebase root_template title="Hello"
"""
...
return bottle.template(welcome_template, ...)

But you cannot do that since root_template will not be found. So you're forced to put root_template into a file root_template.tpl

f10f0bfbd87448 commented 9 years ago

+1 Why have string templates when they're artificially limited like this?

Messy workaround for now is to insert root_template into welcome_template's cache manually before rendering so as to circumvent the whole file search & read operations:

# ... Code to initialise welcome_template and root_template here ...
welcome_template.cache["root_template"] = root_template
# ... Render code here ...
eric-wieser commented 9 years ago

I'd argue that rebasing from a string template is as weird as including one, since a rebase gets translated to an include:

Foo: {{foo}}
% # hypothetical api change allows the following
% include("Bar: {{bar}}", bar=foo.bar)

Why would you ever want to write that, over:

Foo: {{foo}}
Bar: {{foo.bar}}

There seems to be no point in adding this feature.

f10f0bfbd87448 commented 9 years ago

I'm not sure if I understand your objection correctly.

Rebasing is commonly used for "template inheritance", just like it is used in the OP of this issue: You have a common template and then specialised templates that are inserted into this common template via rebasing. Of course this is possible with regular variable substitutions, but it's quite awkward since you have to do the whole composition manually in the render step:

root_template.render(base=welcome_template.render(a=1, b=2), c=3)

This gets hairier for situations with more nesting.

I don't see why there should be any difference between string templates and file templates for this use case.

By the way, I noticed the OP is talking about the rebase keyword, while I'm talking about the rebase function that was introduced in a more recent version.

eric-wieser commented 9 years ago

I was getting confused by the lack of syntax highlighting and syntax error by the OP, and assumed I was looking at tpl code not raw python. Oops.

I now understand that the premise is "All my templates are inline strings in a python server, and I want everything to work as if they were in separate files".

I think the solution here might be to allow registering of string templates to a global name, which is essentially what your hacky solution is doing anyway.

This gets hairier for situations with more nesting.

Can you give me an example of when I'd want to %rebase() twice? I've never done that, and feel I might be missing a trick

f10f0bfbd87448 commented 9 years ago

Can you give me an example of when I'd want to %rebase() twice? I've never done that, and feel I might be missing a trick

I have a situation where I have a root_template common to all pages (basic HTML + CSS skeleton, etc.) and then some pages with similar but slightly different templates. One idea is to take their commonalities and put them in a template (let's call it x_template) that rebases from the root_template. Each sub-page in turn gets its own template which rebases from x_template. Other pages that are "one of a kind" rebase directly from root_template.

It's exactly what one would do if we were talking about classes instead of templates.

I agree that this can be / is a messy solution in its own right, and only works for the simple case of commonalities that "wrap around" the special parts.

I suppose I'm better off composing the templates manually in the render step instead of doing nested rebase.

rhettinger commented 7 years ago

+1 for adding this feature. It would greatly help with command-line experimentation and with putting small template patterns into self-contained scripts.

See: https://stackoverflow.com/questions/46680524

defnull commented 7 years ago

Would not be that hard to do. Just copy a bit of logic from bottle.template() to bottle.SimpleTemplate._include.

But I'm worried about users that think it's okay to pass dynamically created template strings to rebase() or include(). This would quickly bloat the cache with templates that are only rendered once and make everything horribly inefficient. Perhaps emit a warning if the cache grows to big?

codeawn commented 7 months ago

+1 any update about this?