-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Full read-through of the Jinja documentation #4
Comments
https://jinja.palletsprojects.com/en/3.1.x/intro/ says:
I didn't know Jinja had sandboxing! |
Maybe Datasette should ship compiled-ahead-of-time templates? |
https://jinja.palletsprojects.com/en/3.1.x/api/
|
from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
loader=PackageLoader("yourapp"),
autoescape=select_autoescape()
)
|
That would be good! |
|
I guess that could be a function that returns Turns out the |
JInja cache size defaults to 400 - that's 400 templates that will have their compiled versions cached. Increased from 50 in Jinja 2.8. |
You can customize |
|
You can return if not hasattr(obj, 'attr'):
return environment.undefined(obj=obj, name='attr', hint='some hint message here') |
You can reuse the Jinja expression language like this: >>> env = Environment()
>>> expr = env.compile_expression('foo == 42')
>>> expr(foo=23)
False
>>> expr(foo=42)
True Could be interesting to combine this with sandboxing. |
|
Both of these work the same: template.render(knights='that say nih')
template.render({'knights': 'that say nih'}) |
Same arguments as https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Template.generate And There's also a |
>>> t = Template('{% macro foo() %}42{% endmacro %}23')
>>> str(t.module)
'23'
>>> t.module.foo() == u'42'
True Neat trick for exposing template variables to Python! |
|
|
https://jinja.palletsprojects.com/en/3.1.x/api/#the-context
|
|
Policies are a bit weird, they're basically a bunch of additional settings for different things: https://jinja.palletsprojects.com/en/3.1.x/api/#policies e.g. |
Custom filters: https://jinja.palletsprojects.com/en/3.1.x/api/#custom-filters def datetime_format(value, format="%H:%M %d-%m-%y"):
return value.strftime(format)
environment.filters["datetime_format"] = datetime_format Then: {{ article.pub_date|datetimeformat }}
{{ article.pub_date|datetimeformat("%B %Y") }} |
Tests are a cute feature I didn't know about: https://jinja.palletsprojects.com/en/3.1.x/api/#custom-tests
|
OK, so I should mainly use environment globals then. But:
|
https://jinja.palletsprojects.com/en/3.1.x/api/#low-level-api looks fun:
|
https://jinja.palletsprojects.com/en/3.1.x/api/#the-meta-api has two useful things:
Could have fun with that second one building a debug tool of some sort, maybe even a dot graph visualization. |
https://jinja.palletsprojects.com/en/3.1.x/sandbox/ Sandbox actually looks quite good - it's designed to let users craft custom emails for example. It does have one BIG problem though:
Might still work for Datasette Cloud though, since the only thing users will be hurting if they write a bad template is their own instance. |
https://jinja.palletsprojects.com/en/3.1.x/nativetypes/ is interesting - it's designed for non-string-template use cases like config file parsing: >>> env = NativeEnvironment()
>>> t = env.from_string('{{ x + y }}')
>>> result = t.render(x=4, y=2)
>>> print(result)
6
>>> print(type(result))
int |
Import is interesting for macros: https://jinja.palletsprojects.com/en/3.1.x/templates/#import {% import 'forms.html' as forms %}
<dl>
<dt>Username</dt>
<dd>{{ forms.input('username') }}</dd>
<dt>Password</dt>
<dd>{{ forms.input('password', type='password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>
OR
{% from 'forms.html' import input as input_field, textarea %}
|
Lists, tuples and dictionaries are valid Jinja literals. |
Bit surprising (an old bug I think):
|
|
If expressions are neat: https://jinja.palletsprojects.com/en/3.1.x/templates/#if-expression {% extends layout_template if layout_template is defined else 'default.html' %}
{{ "[{}]".format(page.title) if page.title }} |
Lots of built-in filters: https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters |
I like <table>
{%- for row in items|batch(3, ' ') %}
<tr>
{%- for column in row %}
<td>{{ column }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table> That second optional argument is used to fill in missing items. |
There's a I didn't need https://github.com/simonw/datasette/blob/5aa359b86907d11b3ee601510775a85a90224da8/datasette/utils/__init__.py#L849-L858 after all. |
Users on this page: {{ users|map(attribute='username')|join(', ') }}
Users on this page: {{ titles|map('lower')|join(', ') }} |
These test ones are cute: {{ numbers|reject("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }} |
I wonder how good Looks like it uses Which uses these two regexes: _strip_comments_re = re.compile(r"<!--.*?-->", re.DOTALL)
_strip_tags_re = re.compile(r"<.*?>", re.DOTALL) |
The
Implementation: https://github.com/pallets/jinja/blob/52843b5cbf635b37a82ac0b6c901921a8ee076ff/src/jinja2/utils.py#L657-L663 return markupsafe.Markup(
dumps(obj, **kwargs)
.replace("<", "\\u003c")
.replace(">", "\\u003e")
.replace("&", "\\u0026")
.replace("'", "\\u0027")
) |
|
You can test for if a filter is available or not: {% if 'markdown' is filter %}
{{ value | markdown }}
{% else %}
{{ value }}
{% endif %} |
https://jinja.palletsprojects.com/en/3.1.x/templates/#i18n looks very handy: {% trans %}Hello, {{ user }}!{% endtrans %}
{% trans user=user.username %}Hello, {{ user }}!{% endtrans %}
{% trans book_title=book.title, author=author.name %}
This is {{ book_title }} by {{ author }}
{% endtrans %}
{% trans count=list|length %}
There is {{ count }} {{ name }} object.
{% pluralize %}
There are {{ count }} {{ name }} objects.
{% endtrans %}
{% trans trimmed book_title=book.title %}
This is {{ book_title }}.
You should read it!
{% endtrans %}
{{ _("Hello, World!") }}
{{ _("Hello, %(user)s!")|format(user=user.username) }} |
Interesting extension: https://jinja.palletsprojects.com/en/3.1.x/templates/#expression-statement {% do navigation.append('a string') %} |
<pre>{% debug %}</pre> Works if you turn on the extension: https://jinja.palletsprojects.com/en/3.1.x/templates/#debug-statement |
This used to be an extension but is now built in: {% with %}
{% set foo = 42 %}
{{ foo }} foo is 42 here
{% endwith %}
foo is not visible here any longer This too: {% autoescape true %}
Autoescaping is active within this block
{% endautoescape %}
{% autoescape false %}
Autoescaping is inactive within this block
{% endautoescape %} |
Extensions: https://jinja.palletsprojects.com/en/3.1.x/extensions/ Mainly i18n - the others are pretty tiny. You can write your own. |
https://jinja.palletsprojects.com/en/3.1.x/extensions/#module-jinja2.ext
Extensions are pretty low-level AST and parser code. |
https://jinja.palletsprojects.com/en/3.1.x/integration/#babel describes Babel integration, for extracting translatable strings. |
https://jinja.palletsprojects.com/en/3.1.x/switching/ has some short notes on Django template comparisons. |
https://jinja.palletsprojects.com/en/3.1.x/faq/ - only 3 FAQs there. And I'm done! |
I use Jinja enough that I should really do a full read-through of the docs to see what I've missed.
https://jinja.palletsprojects.com/en/3.1.x/
The text was updated successfully, but these errors were encountered: