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.
On the html page
{{ item.filename }}
On the flask routing code :
#app.route("/<username>/<filename>")
def downloadimage(username, filename):
However, this isn't routing the routing method.
What's the issue here ?
You can use the url_for method here.
Use it like this:
{{ item.filename }}
Here, downloadimage is the name of the function added to the required URL, username and filename are the parameters that should be passed to the function.
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 }}