Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Add template keyword to output block unchanged #318

wants to merge 1 commit into from

3 participants


Using javascript templates is tricky because it often requires you to use similar syntax to Tornado templates. While you can use the {{! and {{% syntax, this is often pretty cumbersome for large chunks of javascript templates. I propose we have a verbatim/raw/cdata keyword that would output my template code unchanged.

For more information, see this thread:

Add "verbatim" template keyword that will output the text within the block unchanged


As I said in that thread, I think it's generally a bad idea to put templates inside templates even when their syntaxes don't clash (you'd have to make sure that tornado templates never inject a "{{" into your javascript templates, etc). We now have "{{!" (which is a big improvement over the old "{{'{{'}}"), so I'd need to see a compelling argument for putting JS templates verbatim in tornado templates (as opposed to loading the JS templates from some external source) before adding a new bulk-escaping interface.


The new syntax is indeed an improvement, but using that syntax ensures that I can't develop something using a static page and then copy/paste it over to a Tornado template. Loading the template from an external source doesn't always make sense, such as when I want to have the initial page load contain all of my JS templates.

I can understand your hesitation for adding this code for performance reasons, but I don't understand your hesitation because you don't like the idea of embedding JS inside of Tornado templates. Can you help me understand your reasoning there?


My main objection is about complexity, not performance (especially since it gets even more complex if you relax the requirement for exactly one space on each side of {% end %} to be consistent with everything else). I think that keeping the JS templates out of the tornado templates is actually a better solution for your problem even if the {% verbatim %} block existed. Just keep the JS templates in a separate source file, then use a UIModule to pull them into the rendered page. You can keep your source templates organized in separate files without requiring multiple http fetches from the browser.


Except if you are using tornado for localization, then you need tornado to process the JS template before it goes to the client. This is a good reason to use both templating solutions at once.


But if you're using tornado for localization, then you won't be able to use {% verbatim %} because you still need the translations to be substituted.


I agree, myself, I am using a modified jquery-tmpl library so that they both dont use {{ }} and I can mix the two together. For myself {% verbatim %} is not a solution, but I still need a mix of templates together. If jquery-tmpl offered localization, (or I could find a different good jquery template library), I wouldnt need the mix.


I just noticed that there is already an escape in for jquery templates... so all is cool

        # Template directives may be escaped as "{{!" or "{%!".
        # In this case output the braces and consume the "!".
        # This is especially useful in conjunction with jquery templates,
        # which also use double braces.
        if reader.remaining() and reader[0] == "!":
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 27, 2011
  1. @benweatherman

    Add "verbatim" template keyword that will output the text within the …

    benweatherman authored
    …block unchanged
    Implements issue #317
This page is out of date. Refresh to see the latest.
Showing with 14 additions and 1 deletion.
  1. +14 −1 tornado/
15 tornado/
@@ -533,6 +533,17 @@ def _format_code(code):
def _parse(reader, template, in_block=None):
+ # Skip everything if we're in a verbatim block
+ if in_block == "verbatim":
+ block_end = reader.find("{% end %}")
+ if block_end == -1 or block_end + 1 == reader.remaining():
+ raise ParseError("Missing {%% end %%} block for verbatim")
+ unparsed_text = reader.consume(block_end)
+ # Consume the end block
+ # NOTE: the magic number 9 comes from: len('{% end %}') == 9
+ reader.consume(9)
+ return unparsed_text
body = _ChunkList([])
while True:
# Find next template directive
@@ -658,7 +669,7 @@ def _parse(reader, template, in_block=None):
- elif operator in ("apply", "block", "try", "if", "for", "while"):
+ elif operator in ("apply", "block", "try", "if", "for", "while", "verbatim"):
# parse inner body recursively
block_body = _parse(reader, template, operator)
if operator == "apply":
@@ -669,6 +680,8 @@ def _parse(reader, template, in_block=None):
if not suffix:
raise ParseError("block missing name on line %d" % line)
block = _NamedBlock(suffix, block_body, template)
+ elif operator == "verbatim":
+ block = _Text(block_body)
block = _ControlBlock(contents, block_body)
Something went wrong with that request. Please try again.