Make a conditional in mako template in one line - if-statement

I have this template in Mako templating system:
from mako.template import Template
tmpl = """
% if name:
Hello ${name}
% else:
Hello world
% endif
"""
t = Template(tmpl)
t.render(name="Me")
I want to modify template to have simply one line conditional. Something like this (in jinja syntax):
Hello {% if name %} {{name}} {% else %} world {% endif %}
It seems like Mako needs a line before control structures. I tried put new line with \ but it did not work:
tmpl = """% if name:\ Hello ${name} \ % else:\ Hello world\ % endif"""

We need to use "\n":
tmpl = "% if name:\n Hello ${name}\n % else:\n Hello world\n % endif"
If we use file template, we need to expand "\n". As commented in this post and unicode Chapter in official Mako documentation, one solution could be:
t2 = Template(filename="prova.tmpl", output_encoding='utf-8')
result = t2.render(name="Me").decode("unicode_escape")
print(result)

Related

Using AngularJS template tags in Django [duplicate]

I want to use AngularJS with Django however they both use {{ }} as their template tags. Is there an easy way to change one of the two to use some other custom templating tag?
For Angular 1.0 you should use the $interpolateProvider apis to configure the interpolation symbols: http://docs.angularjs.org/api/ng.$interpolateProvider.
Something like this should do the trick:
myModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
Keep in mind two things:
mixing server-side and client-side templates is rarely a good idea and should be used with caution. The main issues are: maintainability (hard to read) and security (double interpolation could expose a new security vector - e.g. while escaping of serverside and clientside templating by themselves might be secure, their combination might not be).
if you start using third-party directives (components) that use {{ }} in their templates then your configuration will break them. (fix pending)
While there is nothing we can do about the first issue, except for warning people, we do need to address the second issue.
you can maybe try verbatim Django template tag
and use it like this :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
{% verbatim %}
<div ng-app="">
<p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}
If you did separate sections of page properly then you can easily use angularjs tags in "raw" tag scope.
In jinja2
{% raw %}
// here you can write angularjs template tags.
{% endraw %}
In Django template (above 1.5)
{% verbatim %}
// here you can write angularjs template tags.
{% endverbatim %}
We created a very simple filter in Django 'ng' that makes it easy to mix the two:
foo.html:
...
<div>
{{ django_context_var }}
{{ 'angularScopeVar' | ng }}
{{ 'angularScopeFunction()' | ng }}
</div>
...
The ng filter looks like this:
from django import template
from django.utils import safestring
register = template.Library()
#register.filter(name='ng')
def Angularify(value):
return safestring.mark_safe('{{%s}}' % value)
So I got some great help in the Angular IRC channel today. It turns out you can change Angular's template tags very easily. The necessary snippets below should be included after your angular include (the given example appears on their mailing lists and would use (()) as the new template tags, substitute for your own):
angular.markup('(())', function(text, textNode, parentElement){
if (parentElement[0].nodeName.toLowerCase() == 'script') return;
text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
textNode.text(text);
return angular.markup('{{}}').call(this, text, textNode, parentElement);
});
angular.attrMarkup('(())', function(value, name, element){
value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
element[0].setAttribute(name, value);
return angular.attrMarkup('{{}}').call(this, value, name, element);
});
Also, I was pointed to an upcoming enhancement that will expose startSymbol and endSymbol properties that can be set to whatever tags you desire.
I vote against using double parentheses (()) as template tag. It may work well as long as no function call is involved but when tried the following
ng:disabled=(($invalidWidgets.visible()))
with Firefox (10.0.2) on Mac I got a terribly long error instead of the intended logic. <[]> went well for me, at least up until now.
Edit 2012-03-29:
Please note that $invalidWidgets is deprecated. However I'd still use another wrapper than double braces. For any angular version higher than 0.10.7 (I guess) you could change the wrapper a lot easier in your app / module definition:
angular.module('YourAppName', [], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<[');
$interpolateProvider.endSymbol(']>');
});
API docs.
You could always use ng-bind instead of {{ }}
http://docs.angularjs.org/api/ng/directive/ngBind
<span ng-bind="name"></span>
I found the code below helpful. I found the code here: http://djangosnippets.org/snippets/2787/
"""
filename: angularjs.py
Usage:
{% ng Some.angular.scope.content %}
e.g.
{% load angularjs %}
<div ng-init="yourName = 'foobar'">
<p>{% ng yourName %}</p>
</div>
"""
from django import template
register = template.Library()
class AngularJS(template.Node):
def __init__(self, bits):
self.ng = bits
def render(self, ctx):
return "{{%s}}" % " ".join(self.ng[1:])
def do_angular(parser, token):
bits = token.split_contents()
return AngularJS(bits)
register.tag('ng', do_angular)
If you use django 1.5 and newer use:
{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}
If you are stuck with django 1.2 on appengine extend the django syntax with the verbatim template command like this ...
from django import template
register = template.Library()
class VerbatimNode(template.Node):
def __init__(self, text):
self.text = text
def render(self, context):
return self.text
#register.tag
def verbatim(parser, token):
text = []
while 1:
token = parser.tokens.pop(0)
if token.contents == 'endverbatim':
break
if token.token_type == template.TOKEN_VAR:
text.append('{{')
elif token.token_type == template.TOKEN_BLOCK:
text.append('{%')
text.append(token.contents)
if token.token_type == template.TOKEN_VAR:
text.append('}}')
elif token.token_type == template.TOKEN_BLOCK:
text.append('%}')
return VerbatimNode(''.join(text))
In your file use:
from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')
Source:
http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html
You can tell Django to output {{ and }}, as well as other reserved template strings by using the {% templatetag %} tag.
For instance, using {% templatetag openvariable %} would output {{.
I would stick with a solution that uses both django tags {{}} as well angularjs {{}} with a either a verbatim section or templatetag.
That is simply because you can change the way angularjs works (as mentioned) via the $interpolateProvider.startSymbol $interpolateProvider.endSymbol but if you start to use other angularjs components like the ui-bootstrap you will find that some of the templates are ALREADY built with standard angularjs tags {{ }}.
For example look at https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html.
If you do any server-side interpolation, the only correct way to do this is with <>
$interpolateProvider.startSymbol('<{').endSymbol('}>');
Anything else is an XSS vector.
This is because any Angular delimiters which are not escaped by Django can be entered by the user into the interpolated string; if someone sets their username as "{{evil_code}}", Angular will happily run it. If you use a character than Django escapes, however, this won't happen.

Jinja keep indentation on include or macro

I am wondering if there is any way to keep the indentation with jinja when adding a include or macro inside a file. I would like to use jinja to generating a code file. An example would be
File: class.html
class MyClass:
def someOp():
pass
{% include "someOp.html" %}
File: someOp.html
def someOp2():
pass
The result of the template should be:
class MyClass:
def someOp():
pass
def someOp2():
pass
If there any way to make jinja prepend the indent before the include tag for each line in the included file? Or is there any way to customize jinja to do this?
One way is to wrap the include in a macro, then because the macro is a function, its output can be passed through the indent filter:
class MyClass:
def someOp():
pass
{% macro someop() %}{% include "someOp.html" %}{% endmacro %}
{{ someop()|indent }}
By default 'indent' indents 4 spaces and does not indent the first line, you can use e.g. 'indent(8)' to indent further, see http://jinja.pocoo.org/docs/templates/#list-of-builtin-filters for more details.
If what you're including is defined as a macro to begin with then the further wrapper macro is not needed, and you can jump straight to using the indent filter.
I was looking in Jinja2 to achieve the same and got to conclusion aligning multi-line block indentation with the originating Jinja statement is not possible currently.
I've posted a small PR to Jinja to add a new syntax {%* ... %} and {{* ... }} that does exactly this. See the PR for details:
https://github.com/pallets/jinja/pull/919
It would be easier if Jinja provided the facility. It looks like some work was done on this but the issue is currently closed (20 Nov 2019) and the pull request hasn't yet been merged. It could be because things get tricky quite quickly with indents (think of tabs and spaces, for example.)
The following is a simple solution I've found effective for generating Python code which, of course, needs to handle indenting well. It copes with files that use spaces for indentation.
auto_indent() detects the indent level of a variable in a host template, then applies that indent to a piece of text.
import os
import itertools
import jinja2
def indent_lines(text_lines: list, indent: int):
return [' ' * indent + line for line in text_lines]
def matching_line(s, substring):
lineno = s[:s.index(substring)].count('\n')
return s.splitlines()[lineno]
def is_space(c):
return c == ' '
def indentation(line: str) -> int:
initial_spaces = ''.join(itertools.takewhile(is_space, line))
return len(initial_spaces)
def auto_indent(template: str, placeholder: str, content_to_indent: str):
placeholder_line = matching_line(template, '{{ ' + placeholder + ' }}')
indent_width = indentation(placeholder_line)
lines = content_to_indent.splitlines()
first_line = [lines[0]] # first line uses placeholder indent-- no added indent
rest = indent_lines(lines[1:], indent_width)
return os.linesep.join(first_line + rest)
Example:
action_class = """\
class Actions:
def __init__(self):
pass
def prequel(self):
pass
{{ methods }}
def sequel(self):
pass
"""
inserted_methods = """\
def create_branch():
pass
def merge_branch():
pass
"""
if __name__ == '__main__':
indented_methods = auto_indent(action_class, 'methods', inserted_methods)
print(jinja2.Template(action_class).render(methods=indented_methods))
Example output:
>>> python indent.py
class Actions:
def __init__(self):
pass
def prequel(self):
pass
def create_branch():
pass
def merge_branch():
pass
def sequel(self):
pass
I've written a jinja2 extension to work around this long standing issue. It automates the previously proposed solution of using {% filter indent(...) %} by hooking into the preproccess api provided by jinja.ext.Extension.
If you add the extension in your jinja.Environment you can use the following syntax to include templates that get indented correctly into the rest of your template. Notice the indent content directive.
class MyClass:
def someOp():
pass
{% include "someOp.html" indent content %}
The result of rendering then becomes
class MyClass:
def someOp():
pass
def someOp2():
pass

Django templates - split string to array

I have a model field, which stores a list of URLs (yeah, I know, that's wrong way) as url1\nurl2\nurl3<...>. I need to split the field into an array in my template, so I created the custom filter:
#register.filter(name='split')
def split(value, arg):
return value.split(arg)
I use it this way:
{% with game.screenshots|split:"\n" as screens %}
{% for screen in screens %}
{{ screen }}<br>
{% endfor %}
{% endwith %}
but as I can see, split doesn't want to work: I get output like url1 url2 url3 (with linebreaks if I look at the source). Why?
Django intentionally leaves out many types of templatetags to discourage you from doing too much processing in the template. (Unfortunately, people usually just add these types of templatetags themselves.)
This is a perfect example of something that should be in your model not your template.
class Game(models.Model):
...
def screenshots_as_list(self):
return self.screenshots.split('\n')
Then, in your template, you just do:
{% for screen in game.screenshots_as_list %}
{{ screen }}<br>
{% endfor %}
Much more clear and much easier to work with.
Functionality already exists with linkebreaksbr:
{{ value|linebreaksbr }}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#linebreaksbr
Hm, I have partly solved this problem. I changed my filter to:
#register.filter(name='split')
def split(value, arg):
return value.split('\n')
Why it didn't work with the original code?
I wanted to split a list of words to get a word count, and it turns out there is a filter for that:
{{ value|wordcount }}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#wordcount
Apart from whether your original solution was the right approach, I guess the original code did not work because the meaning of the \n is not the same in Python code as it is in HTML: In Python code it means the escaped newline character, in HTML it is just the two separate characters \ and n.
So passing as input parameter \n from the HTML template to the Python code is equivalent to splitting on the Python string \\n: a literal \ followed by a n.

how to write url link in views

I want to write url link in views, and then return to template.
views.py
for platform in platform_list:
if (fail_case.platform==platform):
html_front = "<a href=/home/%s/%s/%s>" % (build, run, fail_case.testResult_id)
html_back = "</a>"
brray.append(html_front + "X" + html_back)
else:
brray.append("")
below is the result(WIN7):
http://img9.imageshack.us/img9/6806/86730486.png
i want to let X be a link, but how can i write it in views.py?
I strongly advise against sending HTML from views. Templates are better suited to do this.
It looks like X is not a "link" as your template is escaping HTML characters. Look up the documentation on how to avoid this. This documentation link shows one way to achieve this. Inside your template you can use the autoescape tag. Something like this:
{% autoescape off %}
{{ template_variable }}
{% autoescape %}

Django shared template

I'm looking how to do the best something like a UserControl in ASP.NET in Django.
For example:
1) There's a Book model defined
2) There's a regular representation of the book which I want to use all over my site (called "book_template.html").
Now let's say I want to use this one representation from 2 views: recent_books_view, popular_books_view. It can be done directly like
from django import template
t = template.Template('My name is {{ name }}.')
book1_context = template.Context({'book': Book1})
book2_context = template.Context({'book': Book2})
book3_context = template.Context({'book': Book3})
...
render_to_response('recent_books.html',
{'content': t.render(book1_context) + t.render(book2_context) + t.render(book3_context)})
render_to_response('popular_books.html',
{'content': t.render(book4_context) + t.render(book5_context) + t.render(book6_context)})
But I'm sure there's a better way...
For example, in ASP.NET you can say in template file "apply for array 'Books' this shared template", and then in the backend you just specify variable 'Books'. Is that possible in Django?
In your python code:
context['books'] = blah blah # Make a list of books somehow.
return render_to_response('popular_books.html', context)
In popular_books.html:
<p>Look, books:</p>
{% for book in books %}
{% include "book.html" %}
{% endfor %}
Finally, in book.html:
<p>I am a book, my name is {{book.name}}</p>
There are more interesting ways to modularize, such as creating a custom tag, so that you could, for example:
<p>Look, books:</p>
{% for b in books %}
{% book b %}
{% endfor %}
I think you're looking for this tutorial Chapter 4 of the Django book: The Django Template System.
See block tags and template inheritance.