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.
Related
My jinja template gets an object which has many variable names, this attributes vary and so their names, I am looking for a way to access this attributes based on a prefix and a for loop:
{% for i in Object.vars %}
<h1> {{ Object.attribute_ + i }} </h1>
{% endfor %}
I'm trying to access Object.attribute_1, Object.attribute_2 and so on. the code above of course won't work, but I can't think on a way of doing this.
Keep in mind that doing too much logic in your template files will cause (long term) issues to maintain your code.
I would say, keep your logic outside of the template and create a list of your objects before rendering the template, using the getattr() function:
for i in Object.vars:
list_of_objects.append(getattr(Object, 'attribute_' + i))
Now when rendering the template pass the list to like that:
render_template('page.html', list_of_objects=list_of_objects)
The canonical way to solve problems like this is to pass a structure such as a list or dict. Dynamic variable names are almost always a terrible idea.
Is it it possible to get the names of the variables in a Mako Template before rendering?
from mako.template import Template
bar = Template("${foo}")
# something like:
# >> print bar.fields()
# ['foo']
Use case:
We have configuration files whereby we specify the metadata from the database to be displayed on a webpage. The client can pick one of a few hundred different pieces of named metadata. There are N slots the client can configure but we don't know in advance which pieces of metadata a particular client would like to have filled in on the form. Because if this when rendering the form we need to know, in advance, what variable names we need to pass for this clients template.
We had thought of having a consistent dictionary with all possible values and passing that in each time but it was unworkable as new available fields are added frequently to the underlying pool of available metadata the client could pick.
Because of this we had hoped to use Mako to template the config files but I can't figure out how to determine with the field values in the template would be so that I can build a full-formed Context to pass to the template.
Unfortunately there is no easy way to get the names of the variables from a template object.
Fortunately there is the mako.codegen._Identifiers class and the sole purpose of its objects is to keep track of the variables during the compilation process.
Unfortunately it is buried deep beneath the Mako API surface, and it is gone after the compilation is done.
Fortunately you can get it without setting up everything Mako sets up when it compiles templates. All you need is the parse tree that you can get by using mako.lexer.Lexer.
Anyway here is the code:
from mako import lexer, codegen
lexer = lexer.Lexer("${foo}", '')
node = lexer.parse()
# ^ The node is the root element for the parse tree.
# The tree contains all the data from a template
# needed for the code generation process
# Dummy compiler. _Identifiers class requires one
# but only interested in the reserved_names field
compiler = lambda: None
compiler.reserved_names = set()
identifiers = codegen._Identifiers(compiler, node)
# All template variables can be found found using this
# object but you are probably interested in the
# undeclared variables:
# >>> print identifiers.undeclared
# set(['foo'])
Chasing Mako variables is no fun. I knocked together this little function to extract the variables from a template - use & improve as you like.
def ListMakoVariables(template):
'''
Extract Mako variables from template.
'''
start = 'XXXX${'
stop = '}YYYY'
makovars = []
splitReady = template.replace('${',start).replace('}',stop)
startParts = splitReady.split('XXXX')
for startStr in startParts:
if '}' in startStr:
makovars.append(startStr.split('YYYY')[0])
vars = set(makovars)
return vars, makovars
FWIW, makovars are in-order, vars are unique but not in order.
I have created a Jinja2 template called lesson.html that defines the basic structure of a lesson. From that, I derive one child template for each actual lesson (since the content of each lesson is different). For example, intro.html, variables.html, lists.html, and functions.html all derive from lesson.html.
Along with slides, exercises, and what-not, each actual lesson has a YouTube video. I want to put the ID of the video in the child template file, but then put the HTML that actually references videos in the parent template (i.e., lesson.html) to ensure that every video is referenced and formatted the same way. For example, I would like lesson.html to look like:
<div class="youtube"><br/>
<iframe title="{{TITLE}}" time="{{TIME}}" src="http://www.youtube.com/embed/{{ID}}"></iframe>
<br/>
</div>
and then have TITLE, TIME, and ID all defined in the child template file itself (since that's the most logical place to store them). My current hack is to create a function that takes these values as arguments and returns a blob of HTML to be inserted in the right place:
{{youtube("Title of this Lecture", "abcde01234", "05:10")|safe}}
but (a) I'd rather use straight template expansion than function calls, and (b) the title, YouTube ID, and time aren't explicitly identified in the lesson template file (which makes them harder to extract for use elsewhere: I can do it with regular expressions, but I'd really rather not).
Is there a clean way to define values in a child template for use in a parent template?
You can use set, DOC are as follows:
Inside code blocks, you can also assign values to variables. Assignments at top level (outside of blocks, macros or loops) are exported from the template like top level macros and can be imported by other templates.
Same question can be found here.
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.
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')