app_template_filter with multiple arguments
Question:
How can I pass two arguments to app_template_filter
(doc)? This works well if I use only one argument. But in this case, I need two.
@mod.app_template_filter('posts_page')
def posts(post_id, company_id):
pass
{{ post.id, post.company.id | posts_page }}
Error:
TypeError: posts_page() takes exactly 2 arguments (1 given)
Answers:
From the Jinja docs,
Variables can be modified by filters. Filters are separated from the variable by a pipe symbol (|) and may have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is applied to the next.
Filters are designed to modify one variable at a time. You’re looking for a context processor
:
Variables are not limited to values; a context processor can also make functions available to templates (since Python allows passing around functions)
For example,
@app.context_processor
def add():
def _add(int1, int2):
return int(int1) + int(int2)
return dict(add=_add)
can be used in the template as
{{ add(a, b) }}
You can adopt this as your posts_page
method:
@app.context_processor
def posts_page():
def _posts_page(post_id, company_id):
# ...
return value
return dict(posts_page=_posts_page)
While you may use a context processor, it may not always be what you want.
The docs snippet in the accepted answer says:
[Filters] may have optional arguments in parentheses.
So, looking at the asker’s template filter:
@mod.app_template_filter('posts_page')
def posts(post_id, company_id):
pass
The following is valid in the template:
{{ post.id|posts_page(post.company_id) }}
This is how I do it, but the purists might not like it, it might not be "pythonistic" given the "modify one variable" thing. However, I realize that modifying one variable might required input from several values.
Template:
{% set args = { 'post_id': post.id, 'company_id': post.company.id } %}
...
{{ args | posts_page }}
Server:
@mod.app_template_filter('posts_page')
def posts(args):
post_id = args['post_id']
company_id = args['company_id']
How can I pass two arguments to app_template_filter
(doc)? This works well if I use only one argument. But in this case, I need two.
@mod.app_template_filter('posts_page')
def posts(post_id, company_id):
pass
{{ post.id, post.company.id | posts_page }}
Error:
TypeError: posts_page() takes exactly 2 arguments (1 given)
From the Jinja docs,
Variables can be modified by filters. Filters are separated from the variable by a pipe symbol (|) and may have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is applied to the next.
Filters are designed to modify one variable at a time. You’re looking for a context processor
:
Variables are not limited to values; a context processor can also make functions available to templates (since Python allows passing around functions)
For example,
@app.context_processor
def add():
def _add(int1, int2):
return int(int1) + int(int2)
return dict(add=_add)
can be used in the template as
{{ add(a, b) }}
You can adopt this as your posts_page
method:
@app.context_processor
def posts_page():
def _posts_page(post_id, company_id):
# ...
return value
return dict(posts_page=_posts_page)
While you may use a context processor, it may not always be what you want.
The docs snippet in the accepted answer says:
[Filters] may have optional arguments in parentheses.
So, looking at the asker’s template filter:
@mod.app_template_filter('posts_page')
def posts(post_id, company_id):
pass
The following is valid in the template:
{{ post.id|posts_page(post.company_id) }}
This is how I do it, but the purists might not like it, it might not be "pythonistic" given the "modify one variable" thing. However, I realize that modifying one variable might required input from several values.
Template:
{% set args = { 'post_id': post.id, 'company_id': post.company.id } %}
...
{{ args | posts_page }}
Server:
@mod.app_template_filter('posts_page')
def posts(args):
post_id = args['post_id']
company_id = args['company_id']