I'm adding some globals in my handler that should be available to all templates, including macros.
jinja_env.globals.update({
"SOME_CONSTANT": SOME_CONSTANT_1,
})
This works fine when I use it inside a macro like this:
{% macro is_some_constant(some_str) -%}
some_str == SOME_CONSTANT
{%- endmacro %}
But I get an undefined error when I try to use a global as a default arg to the macro:
{% macro test_something(something=SOME_CONSTANT) -%}
...
{%- endmacro %}
Result: NameError: global name 'l_SOME_CONSTANT' is not defined
Is this expected? I found this related issue which is claimed to be fixed by this PR, but still running into this. The workaround mentioned in the first link does work, but is kind of silly and annoying:
{% set SOME_CONSTANT = SOME_CONSTANT %}
{% macro test_something(something=SOME_CONSTANT) -%}
...
{%- endmacro %}
Oh, I realized I'm on jinja2 v2.8, and the fix PR was merged into 2.9 (I think). So perhaps that fixes the problem.
For now, I'll just use the hacky workaround.
Related
I defined a macro that starts with:
{% macro my_macro(table, first=false) %}
{%- if first -%} WITH
{%- else -%} ,
{% endif %}
tmp AS (...
In the compiled SQL I see this is completely ignored. If I paste this exact same block after the first CTE, it inserts fine. If I put any text before the if-block, it will also render the text + content of if-block.
I don't understand this behaviour. How can I make this macro work leading either with WITH or ","?
Even if I replace first with true it doesn't show up.
Additional information:
I'm working with BigQuery and dbt version 0.18.2
After trial and error I realised that using "-" to reduce white space on the first line somehow removes the text coming after it as well.
So
{%- if first -%}
WITH
...
Doesn't work, but
{% if first %}
WITH
...
is fine. It was a simple fix, but I doubt this is expected behaviour.
interesting problem! A couple of questions:
What database are you working with?
What version of dbt are you working with?
Where does first come from in your query?
On Azure Synapse and with dbt version 0.18.1, I was able to successfully use the following:
{% set first = true %}
{%- if first -%}
WITH
{%- else -%} ,
{% endif %}
top_100 AS (
SELECT 100 AS MyNumber
),
top_10 AS (
SELECT TOP 10 * FROM top_100
)
SELECT * FROM top_10
I'm building an admin for Flask and SQLAlchemy, and I want to pass the HTML for the different inputs to my view using render_template. The templating framework seems to escape the HTML automatically, so all <"'> characters are converted to HTML entities. How can I disable that so that the HTML renders correctly?
To turn off autoescaping when rendering a value, use the |safe filter.
{{ something|safe }}
Only do this on data you trust, since rendering untrusted data without escaping is a cross-site scripting vulnerability.
MarkupSafe provides Jinja's autoescaping behavior. You can import Markup and use it to declare a value HTML safe from the code:
from markupsafe import Markup
value = Markup('<strong>The HTML String</strong>')
Pass that to the templates and you don't have to use the |safe filter on it.
From the Jinja docs section HTML Escaping:
When automatic escaping is enabled everything is escaped by default
except for values explicitly marked as safe. Those can either be
marked by the application or in the template by using the |safe
filter.
Example:
<div class="info">
{{data.email_content|safe}}
</div>
When you have a lot of variables that don't need escaping, you can use an autoescape override block:
{% autoescape false %}
{{ something }}
{{ something_else }}
<b>{{ something_important }}</b>
{% endautoescape %}
For handling line-breaks specifically, I tried a number of options before finally settling for this:
{% set list1 = data.split('\n') %}
{% for item in list1 %}
{{ item }}
{% if not loop.last %}
<br/>
{% endif %}
{% endfor %}
The nice thing about this approach is that it's compatible with the auto-escaping, leaving everything nice and safe. It can also be combined with filters, like urlize.
Of course it's similar to Helge's answer, but doesn't need a macro (relying instead on Jinja's built-in split function) and also doesn't add an unnecesssary <br/> after the last item.
Some people seem to turn autoescape off which carries security risks to manipulate the string display.
If you only want to insert some linebreaks into a string and convert the linebreaks into <br />, then you could take a jinja macro like:
{% macro linebreaks_for_string( the_string ) -%}
{% if the_string %}
{% for line in the_string.split('\n') %}
<br />
{{ line }}
{% endfor %}
{% else %}
{{ the_string }}
{% endif %}
{%- endmacro %}
and in your template just call this with
{{ linebreaks_for_string( my_string_in_a_variable ) }}
Use the safe filter in your template, and then sanitize the HTML with the bleach library in your view. Using bleach, you can whitelist the HTML tags that you need to use.
This is the safest, as far as I know. I tried both the safe filter and the Markup class, and both ways allowed me to execute unwanted JavaScript. Not very safe!
When i use
{% include folder1/folder1_1/img.jpg %}
it works perfectly, But when i try to generate the filename dynamically let's say :
{%capture filename %} {{'folder1/folder1_1/'}}{{ images[0] }}{{ '.jpg' }}{% endcapture %}
{% include {{ filename }} %}
with images[0] = 'img' for example, i get the error that says :
Liquid Exception: Invalid syntax for include tag. File contains
invalid characters or sequences ...
I Don't understand why including file by providing the complete path(static path) works whereas generating the filename dynamically won't work !
Any help would be more than appreciated.
After more research on the internet it seems that dynamic filename paths can't be added due to the fact that the included files are calculated and added at the compilation phase and not at run time phase.
And compilation phase means dynamic paths aren't yet recognized.
Maybe more luck with :
{% capture filename %}folder1/folder1_1/'{{ images[0] }}.jpg'{% endcapture %}
{% include {{ filename }} %}
Is it possible to do something like this in jinja2:
my_list = ['foo1', 'bar1', 'foo2', 'bar2'] # could be any number of foo's and bar's
[i for i in my_list if 'foo' in i]
I was looking at map and join, something like:
{% my_list|map('???')|join(' ') %}
But I can't find a filter that would like me do any sort of wildcard searches. The two closest ones look like 'sameas' and 'equalto' but those don't quiet work.
If you're using a recent version of Jinja2 (2.7 or later), there's a new filter called 'select', which seems to do what you want. jinja.pocoo.org/docs/dev/templates/#select You will probably have to write your own test for this, and pass it into the jinja2 object when you instantiate it.
{{ foobars|select("test") }}
If you're on an even more up to date version (2.8 or later), you can also use block assignments http://jinja.pocoo.org/docs/dev/templates/#block-assignments
{% set my_foo_bars %}
{%- for item in my_list %}
{%- if item %}
{{item}}
{% endif -%}
{% endfor -%}
{% endset %}
If you're stuck on an older version (like the jinja2 from google app engine), you would probably be best doing the processing before passing it into the template, if possible.
I have some code that I've been repeating a lot in one of my jinja2 templates. When I've been turning a string into a link I want to check to see if it has a trailing / at the end and if it does then truncate it. This is what I'd like it to look like.
{% macro remove_trailing_slash(path) %}
{% if path[-1:] == '/' %}
{{ path[:-1] }}
{% else %}
{{ path }}
{% endif %}
{% endmacro %}
The problem I'm having is figuring out how to pass the modified path back to the original caller. I can't seem to find a return statement in the jinja2 docs.
This is something that would be better done with a filter in Jinja, rather than a macro.
In my understanding macros are for reusing pieces of logic, they don't really map to functions in Python (it would be within the Jinja compiler's right to copy the contents of the macro to every place the macro is invoked). Filters, on the other hand, are designed to manipulate the template's data before it is passed on to the "output stream".
If you register a filter with the Jinja environment, then you can do something like this:
{{ one_url | remove_trailing_slash }}
{{ another_url | remove_trailing_slash }}
If you are doing this all over your templates, you may be better off sanitizing these values before even passing them off to your templates.
You can also create a macro to wrap this pattern:
{% macro link(url) %}
{{ url | remove_trailing_slash }}
{% endmacro %}