Jinja2: Looking for a View-Helper - python

I'am new to the Jinja2 template engine. Is there something like the view-helpers from Zend Framework? Can i create simple functions and reuse them all over all my template-files?
Something like this?
#somewhere in my python code:
def nice_demo_function(message):
""""return a simple message"""
return message
So i can to use that:
<!-- now in my template-file -->
{% nice_demo_function('yes, this works great!') %}

There are a number of ways you can expose helper functions to your templates. You could define them using macros, and then import them into templates that use them. You could add functions to the globals attribute of your Template objects, or pass them to the render() method. You could subclass Template to do the same without having to repeat yourself each time. If you want to get really fancy, you could look into writing extensions as well (but you probably don't need to go that deep).

At some point you will have created a Jinja2 environment. The environment has an attribute on it called filters which is a dict that maps names to functions. So what you want to do is:
def my_helper(value):
return "-~*#--- %s ---#*~-" % value
env = Jinja2.Environment(...)
env.filters['my_helper'] = my_helper
Now in your template you can do:
<p>The winner is {{ winner | my_helper }}</p>
And your function will be called with the value of the variable, in this case winner. If you are using Pylons, this all happens in config/environment.py.

Related

Get list of variables from Jinja2 template (parent and child)

I'm trying to get a list of variables from a Jinja2 template.
test1.j2:
some-non-relevant-content
{{var1}}
{% include 'test2.j2' %}
test2.j2:
another-text
{{var2}}
I can get variables from test1 easily:
env = Environment(loader=FileSystemLoader(searchpath='./Templates'))
src_t = env.loader.get_source(env, 'test1.j2')[0]
parsed_t = env.parse(source=src_t)
t_vars = meta.find_undeclared_variables(ast=parsed_t)
Problem is, I can only get variables from the parent template with get_source.
Obviously, I can not feed class template object to parse method as well.
Is there any way to build the full list? {'var1', 'var2'} in my case.
Ideally by using Jinja2 API. Minimum custom code.
Found a way to code that without a big pain.
meta.find_referenced_templates helps to load all child templates when applied recursively. When done, it's trivial to get variables from all templates in a single list.

Exposing global data and functions in Pyramid and Jinja 2 templating

I have a base template for when a user is logged in, and on that base template, I need to add user specific options in a drop down menu. This drop down menu with options must be constant across all handlers, i.e., any time the base template is invoked (extended) with a child template.
Other than performing the necessary DB query, assigning the query results to a variable, and passing that variable to every handler (there are many), how can I consolidate this into one query and one variable, which gets passed directly to the base template? I am using jinja2 templates as well.
I would hate to do something so cumbersome in exchange for something far more simple and maintainable.
Any ideas? Thanks.
EDIT
So I still haven't found anything that's exactly what I'm looking for; however, I decided to at least make some headway in the interim. So, I made a custom decorator that takes a view's returned dict() and appends the appropriate data to it. For example:
def get_base_data(func):
def wrapper(request):
d = func(request)
user_id = request.user.id # used in query
contact_group_data = ContactGroups.query.filter(...criteria...).all()
d['contact_group_data'] = contact_group_data
return d
return wrapper
Now, I can at least decorate each method very concisely and simply by putting:
#view_config(...)
#get_base_data
def my_handler(request):
pass # rest of code...
This is one of most inobvious things in Pyramid and took a while to find for me, too.
You can modify the global template context in BeforeRender event.
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/hooks.html#using-the-before-render-event
Alternatively, you could use class based views, inherit all your views from one base view class which has get_base_data(), then the class instance is passed to the template context to all your views and then you could extract the data with {{ view.get_base_data }}.
http://ruslanspivak.com/2012/03/02/class-based-views-in-pyramid/
I vouch for the latter approach as it is more beautiful, predictable and easier to maintain engineering wise.

How can I use Django built-in filters with Jinja2 using Appengine SDK?

I've tried several different ways a while ago, each of them gave a different exception, so I gave up and decided to manually write filters when I need them. But I'm missing the native escapejs and other useful but simple filters.
There are several related questions and answers, but as far as I see none of them gives a seamless way to implement this. I guess the main problem is that django filters routines are tied too much to the django environment.
Please answer only if you managed to use built-in django filters in the Appengine SDK environment, from my experience it's harder compared to a normal environment, as Appengine environment is limited
Template tags in the Django template engine are simple functions that accept values and parameters. They can all be accessed directly in the source code.
This is output from IPython:
In [173]: from django.template.defaultfilters import date
In [174]: date??
Type: function
String Form:<function date at 0xa2935f0>
File: /usr/local/python/thor/lib/python2.7/site-packages/django/template/defaultfilters.py
Definition: date(value, arg=None)
Source:
#register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if not value:
return u''
if arg is None:
arg = settings.DATE_FORMAT
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
Most of the Django-specific magic resides in the decorator (register.filter) and in the way that the language resolves calls when you type {% load <template library> %} in your template. Look for the definitions in <module>.templatetags modules. Built-ins are located in django.template.defaulttags and django.template.defaultfilters.
If Jinja2 has a way to define new template filters (which it probably does), then you could simply wrap handmade template filters to actual Django functions.
So basically, just create Jinja2 filters that point to the actual Django function definitions.
Edit:
If you do not have access to the actual Django functions, just copy-paste the source code and remove or adapt Django-specific stuff.
The escapejs filter is actually a call to this function in django.utils.html:
_base_js_escapes = (
('\\', r'\u005C'),
('\'', r'\u0027'),
('"', r'\u0022'),
('>', r'\u003E'),
('<', r'\u003C'),
('&', r'\u0026'),
('=', r'\u003D'),
('-', r'\u002D'),
(';', r'\u003B'),
(u'\u2028', r'\u2028'),
(u'\u2029', r'\u2029')
)
# Escape every ASCII character with a value less than 32.
_js_escapes = (_base_js_escapes +
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
for bad, good in _js_escapes:
value = mark_safe(force_unicode(value).replace(bad, good))
return value
I alluded to this in my comment, but I'll be more specific here since I have more space. Django is an end-to-end web application framework, which happens to include its own template language, that for lack of a better term is just called the "Django template language". All the template tags and filters in the docs are specific to that language.
If you choose to use Jinja2, you choose to use that template language's structures to the exclusion of Django's. (Obviously the model and view stuff is a separate layer, but in principle, those could be swapped too--it's all loosely coupled.) So the Django docs for templating are no good to you in that case. If you want to format a float in Jinja2, it looks like you need to use the format filter, according to the Jinja docs.
Without more info, I really can't say what's causing your ImportError, but floatformat is not going to work in a Jinja2 template, so maybe that has something to do with it.

store html templates in docstrings?

I am using Flask to write a web service for an internal app here at my work. Many of the web services URI's return HTML partials, and I am trying to figure out a clean way to store the html template strings. I don't want to put the template strings in separate files, since they are usually only a few lines long and I don't want to have 20 template files that each have 3 lines in them. I was thinking about defining a function's html template string in the docstring of the function, as I feel like that would serve multiple purposes. It would serve as documentation, basically saying "this is what I output", as well as keeping me from having to store 3-line templates strings in separate files. Here is what I am talking about:
#app.route('/path/to/my/resource/<int:_id>')
def some_resource(_id):
"""
<select id="resource-{{ resource.id }}" class="resource">
{% for choice in choices %}
<option id="choice-{{ choice.id }}" value="{{ choice.id }}">
{{ choice.text }}
</option>
{% endfor %}
</select>
"""
# retrieving resource, etc...
return render_template_string(some_resource.__doc__, **kwargs)
I don't know whether this would be a nightmare to maintain or not...any thoughts?
I think its a bad plan.
Docstrings are for documentation, the template is not documentation. Documentation is supposed to describe what the function is being used for. An HTML template is a poor substitute for that.
You can use multi-line strings to hold your template, and thats probably a good idea. You don't gain anything by making them docstrings.
It's certainly an interesting idea, and following the example of doctest, it's not entirely unheard of to put functionally-useful things in your docstrings instead of just text. The obvious drawback is that then there's no documentation in the docstring. Now, this may or may not be a huge problem if the methods are not something that programmers will likely need documentation on via help() (or by auto-generated docs using the docstrings).
However, why not either:
just use a local string variable - the downside would be that you can't get at it via __doc__ from outside the scope of the function
if it's just used that once, just put it into the render_template_string call - same drawbacks as #1, but also doesn't apply if it's used more than once
create another decorator that takes this string as an argument - especially if it just follows the pattern above where you're just using it the once and you're always doing the same call at the end, this would allow you to pull it out of that method
In some templating engines, if an object has a __html__ method, it's output is treated as a safe (escaped) string.
def fn(x):
bla = x
fn.__html__ = lambda : '''
<h1>Headline</h1>
<p>lorem ipsum</p>
'''

Using Django view variables inside templates

this is a rather basic question (I'm new to Django) but I'm having trouble using a variable set in my view inside my template. If I initialize a string or list inside my view (i.e. h = "hello") and then attempt to call it inside a template:
{{ h }}
there is neither output nor errors. Similarly, if I try to use a variable inside my template that doesn't exist:
{{ asdfdsadf }}
there is again no error reported. Is this normal? And how can I use my variables within my templates. Thanks!
In order to have access to a variable in a template, it needs to be in the the context used to render that template. My guess is you aren't passing a context dictionary to the template when you render it.
http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render-to-response
The "dictionary" referenced there is a dictionary that contains all the variables you want to have available in the context. For example:
return render_to_response('your_template.html', {'h': h})
As far as the "no error" error goes... That's the default setting for an invalid template variable. You can change that in the project's settings if you'd like.
http://docs.djangoproject.com/en/dev/ref/settings/#template-string-if-invalid
You can also use
return render(request, 'your_template.html', {'h':h, 'var1':var1})
Refer to the latest manual on https://docs.djangoproject.com/es/1.9/topics/http/shortcuts/
Yes! This is normal. Such errors in templates fail silently and this is expected in Django.
to render properly template use render_to_response('your_template.html', {'h':h}) (there is also a nasty shortcut render_to_response('your_template.html', locals()) if your context dictionary is very big)
here is some explanation with examples: http://www.djangobook.com/en/beta/chapter04/ (section 'How invalid variables are handled')

Categories