I have a route defined like this:
#app.route('/magic/<filename>')
def moremagic(filename):
pass
And now in a template I want to call that route using url_for() like so:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
I have tried:
Click to see magic happen
That throws a jinja2.TemplateSyntaxError: expected token ':' got }
Can anyone suggest how to get the {{ name }} that appears in the template into the url_for() so that when I click I call the correct app.route?
Everything inside the {{ ... }} is a Python-like expression. You don't need to use another {{ ... }} inside that to reference variables.
Drop the extra brackets:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
(Note that the url_for() function takes the endpoint name, not a URL path; the name defaults to the name of the function, moremagic in your example).
Related
I have a route defined like this:
#app.route('/magic/<filename>')
def moremagic(filename):
pass
And now in a template I want to call that route using url_for() like so:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
I have tried:
Click to see magic happen
That throws a jinja2.TemplateSyntaxError: expected token ':' got }
Can anyone suggest how to get the {{ name }} that appears in the template into the url_for() so that when I click I call the correct app.route?
Everything inside the {{ ... }} is a Python-like expression. You don't need to use another {{ ... }} inside that to reference variables.
Drop the extra brackets:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
(Note that the url_for() function takes the endpoint name, not a URL path; the name defaults to the name of the function, moremagic in your example).
I'm trying to render a jinja2 template in my service (not using flask, just pure jinja2 and constructing a jinja2 Environment.
Let's say I have the following filter defined
import jinja2
#jinja2.contextfilter
def my_function(context):
if context.get('my_var'):
return "hello"
else:
return "world"
Super simplified example, but the point of it is that I have some logic that conditionally returns a value based on some variable passed into the context.
Also, I'm using jinja2 2.11 or something like that, which is why I'm using #contextfilter instead of #pass_context.
I've added this filter to my environment using env.filters['my_function'] = my_function
In rendering the template, I'm calling
template = env.get_template('my_template.html')
template.render({'my_var': 'some_value'})
where the template might look something like
... some html here
{{ my_function }}
... some more html
This doesn't actually return "hello", and instead just is empty/blank.
I managed to get it by passing in a dummy variable
#jinja2.contextfilter
def my_function(context, value):
.... code is the same
And then in the template, I call it with {{ 'hi' | my_function }}. But obviously this is just a hack and not very desirable.
So my question is, how can I call a jinja2 filter function that only takes the context in as an argument? I've tried {{ my_function() }} which returns the error UndefinedError: 'my_function' is undefined, and {{ | my_function }}, which returns the error TemplateSyntaxError: unexpected '|'`
Or is there some other jinja2 construct I should be using?
Edit: my suspicion is that jinja2 uses the | to identify a filter vs a variable, and since I don't have |, then it tries to just render the variable my_function from the context, and since it doesn't exist in the context, it just outputs an empty string.
Jinja2 calls these kind of functions global functions (like range()), not filters. Just change filters to globals in this line:
env.globals['my_function'] = my_function
And then you can call your function in the templates: {{ my_function() }}.
jinja_code.py
import jinja2
env=jinja2.Environment(loader=FileSystemLoader(searchpath="./"))
template=env.get_template('file.j2')
render_template=template.render(test1="TEST1",test2="TEST2")
print(render_template)
file.j2
{{ context.test1 }}
I'm learning Jinja2 and I understood that context are the variables that are passed to Template but when I execute the above code, i get the below error
jinja2.exceptions.undefinederror: 'context' is not defined
I've read the docs and I couldn't understand it completely. Can you please explain what is context and how it is used to access the variables?
Context contains the dynamic content that you want to inject in your template when it is being rendered.
In your example, the file file.j2 must have the following content:
{{ test1 }}
As context is not a variable but the collection of all variables you pass to the template. test1 and test2 are part of the context.
I'm using Django and Python 3.7. In my template, I can see the output of this
{{ articlestat.article.website.id }}
which is "4". I have a dictionary, passed to my context, whose keys are numbers. If I do the following
{{ website_stats.4 }}
I see a value printed. However if I do this
{{ website_stats[articlestat.article.website.id] }}
I get the error
Could not parse the remainder: '[articlestat.article.website.id]' from 'website_stats[articlestat.article.website.id]'
So my question is, how do I access the value of a dictionary on my template when the key is stored in a variable? I'm not in a position to hard-code the keys.
You cannot access the dict keys with this syntax in django templates. Usually, we access the key with {{ my_dict.my_key }}.
But of course this will not work if you pass a variable like articlestat.article.website, all the dots would messing things up. Even without the dots, the name following the dot cannot be a variable, the template engine uses this name as a string to lookup for a key or a property of this object. (check https://code.djangoproject.com/ticket/12486)
If you really cannot match the values from the view, where it is easier to process, this will require a simple custom template filter.
in a folder templatetags in your app, add a file named custom_filters.py with this code :
from django.template import Library
register = Library()
#register.filter
def lookup(d, key):
return d.get(key) # simple access here, you can also raise exception in case key is not found
in the templates where you need such dict access, add {% load custom_filters %} on top, and use this syntax to call your values :
{{ website_stats|lookup:articlestat.article.website.id }}
How can I call a method, pass multiple parameters to it and render the result in a html template? I can't find a simple solution which works in all circumstantials. I'm aware about #register.filter and #register.simple_tag but there's alway an error being thrown. If it's not thing, it's another. For example, simple_tag works when I render it, but throws an error when I call if.
So how can I call a method from an html template in the following ways:
{{method1(a, b)}}
{% if method1(a, b) == some_value %} {{method1(a, b)}} {%endif%}
Note I don't need advice like "you're doing something wrong, you should change your architecture" because that's not the case here. I just a simple way to do what I want. In Rails, for example, I can do it very, very easily.
You can use an assignment tag to assign the value received from the template tag into a variable which then can be used anywhere in the template.
#register.assignment_tag
def method1(a,b):
...
Then in your template you can call this template tag and assign its value to a variable method_value.
{% method1 a b as method_value %}
Then use this variable in the template.
{{method_value}}
{% if method_value == some_value %} {{method_value}} {%endif%}