![Page 1: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/1.jpg)
Django đź’–
Jinja2 Aymeric Augustin DjangoCong 2016
Jardin des Plantes, Avranches, 9 avril 2016
![Page 2: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/2.jpg)
👋 I’m Aymeric
2
Core Developersince 2011
Chief Technical Officersince 2015
• Time zones• Python 3• Transactions• App loading• Jinja2
First peer-to-peerinsurance broker
in France
We’re hiring!
Amalfi
![Page 3: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/3.jpg)
Why Jinja2?
3
Aren’t Django templates just fine?
![Page 4: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/4.jpg)
4
Jinja2 is fast.10-20x faster than Django templates.
Image from http://www.gentside.com/dragster/wallpaper
![Page 5: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/5.jpg)
5
Django templates are slow.10-20x slower than Jinja2.
Image from https://commons.wikimedia.org/wiki/File:Grand_bi_sur_la_terrasse_Dufferin_vers_1900.jpg
![Page 6: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/6.jpg)
Let’s try it on the fractalideas.com home page!
6
>>> import statistics, timeit
>>> setup = \
... "from django.template.loader import render_to_string"
>>> round(statistics.median(timeit.repeat(
... "render_to_string('home.html', using='django')",
... setup, repeat=10, number=1000)), 2)
1.18 # ms
>>> round(statistics.median(timeit.repeat(
... "render_to_string('home.html', using='jinja2')",
... setup, repeat=10, number=1000)), 2)
0.35 # ms
![Page 7: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/7.jpg)
Let’s try it on the fractalideas.com home page!
• More than three times faster!
• Not even a millisecond faster.
• Page loads 0.004% faster with a cold cache.
7
![Page 8: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/8.jpg)
Let’s try it on the fractalideas.com home page!
• More than three times faster!
• Not even a millisecond faster.
• Page loads 0.02% faster with a warm cache.
8
![Page 9: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/9.jpg)
Template rendering speed (often) doesn’t matter
• Light content? Anything is fast enough
• Heavy static content? Pre-render & cache it
• Heavy dynamic content? Render in the browser
• If you’re thinking about switching template languages, consider both server-side and client-side options (React)
• Until you’ve optimized everything else, templates are unlikely to be a bottleneck
9
![Page 10: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/10.jpg)
Why Jinja2?
10
Aren’t Django templates just fine?
![Page 11: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/11.jpg)
– http://jinja.pocoo.org/docs/
“Jinja2 is a modern and designer-friendly templating language for Python,
modelled after Django’s templates.”
11
![Page 12: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/12.jpg)
Advantages of Jinja2
• More comfortable for developers
• Django expects templates to be written by “designers”
• Easier to customize
• Try writing a Django template tag without the docs
• Meaningfully faster in some use cases
• Template-based widget rendering (#15667)
12
![Page 13: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/13.jpg)
Drawbacks of Jinja2
• Less common than Django templates
• Many authors of pluggable apps don’t know where to start (yet)
• Targets experienced developers
• Docs suggest handling escaping manually for performance
• Scoping behavior for included blocks is declarative
• etc.
13
![Page 14: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/14.jpg)
Features of Jinja2 — from its docs’ homepage
• sandboxed execution
• powerful automatic HTML escaping system for XSS prevention
• template inheritance
• compiles down to the optimal python code just in time
• optional ahead-of-time template compilation
• easy to debug (…)
• configurable syntax14
sounds important (to me)
![Page 15: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/15.jpg)
– paraphrased from http://jinja.pocoo.org/docs/
“Jinja2 is a templating language for Python designed for experienced developers, modelled after Django’s templates.”
15
![Page 16: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/16.jpg)
Third-party solutions
• Coffin (2008 - reborn in 2015)
• Alternative APIs such as render()
• Jingo (2010)
• Template loader (class-based API since Django 1.2)
• Django-Jinja (2012)
• More opinionated and full-featured template loader
16
![Page 17: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/17.jpg)
Templates in Django < 1.8
17
Discussed for historical purposes only — these versions are unsupported!
![Page 18: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/18.jpg)
Django < 1.8 - Rendering a template
18
# django/template/loaders.py (simplified)
def render_to_string(template_name, dictionary):
template = get_template(template_name, dirs)
context = Context(dictionary)
return template.render(context)
![Page 19: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/19.jpg)
Django < 1.8 - Rendering a template
19
# django/template/loaders.py (simplified)
def get_template(template_name):
template, origin = find_template(template_name)
return Template(template, origin, template_name)
![Page 20: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/20.jpg)
Django < 1.8 - Rendering a template
20
# django/template/loaders.py (simplified)
def find_template(name, dirs=None):
global template_source_loaders
if template_source_loaders is None:
... # init from settings.TEMPLATE_LOADERS
for loader in template_source_loaders:
... # try loading with loader(name)
raise TemplateDoesNotExist(name)
global configuration
![Page 21: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/21.jpg)
Django < 1.8 - Actually rendering a template
21
# django/shortcuts.py (drastically simplified)
def render(request, template_name, dictionary):
template = get_template(template_name, dirs)
context = RequestContext(request, dictionary)
return HttpResponse(template.render(context))
strong coupling
![Page 22: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/22.jpg)
Context processors are a poor API
• How many context processors depend on request?
• Aside from the request context processor, that is.
• How hard is it to make a context processor lazy?
• In order to avoid overhead in templates that don’t need it.
• Just an API for {{ global_func(request) }}?
• Django templates cannot call functions with arguments.
22
![Page 23: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/23.jpg)
Multiple templates engines in Django ≥ 1.8
23
If templates weren’t boring, they’d have been fixed earlier.
![Page 24: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/24.jpg)
24
![Page 25: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/25.jpg)
25
![Page 26: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/26.jpg)
26
![Page 27: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/27.jpg)
Plan
1. Write a Django Enhancement Proposal (DEP)
• Lots of reading; some writing
2. Refactor Django templates as a library (optional)
• Actually not optional
3. Implement the DEP
• Sounds easy
27
![Page 28: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/28.jpg)
Concept
28
django.template.*
django.template.loader
d.t.backends.django d.t.backends.jinja2
django.template.* jinja2
![Page 29: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/29.jpg)
– DEP 182
“this project avoids encoding the legacy of the Django template language in APIs”
29
![Page 30: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/30.jpg)
Jinja2 for Djangonauts
30
Wake up — this is the “just do this” section.
![Page 31: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/31.jpg)
Install Jinja2
31
$ pip install jinja2
![Page 32: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/32.jpg)
Define a Jinja2 environment
32
# project/jinja2.py
from jinja2 import Environment
def environment(**options):
options.setdefault('extensions', []).extend([...])
env = Environment(**options)
env.filters.update({ ... })
env.globals.update({ ... })
env.tests.update({ ... })
return env
![Page 33: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/33.jpg)
Install translations (optional)
33
# project/jinja2.py
from django.utils import translation
def environment(**options):
# ...
env.install_gettext_translations(translation,
newstyle=True)
# ...
return env
![Page 34: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/34.jpg)
Point the TEMPLATES setting to the environment
34
TEMPLATES = [{
'BACKEND': 'django.template.backends'
'.jinja2.Jinja2',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'OPTIONS': {
'environment': 'project.jinja2.environment',
},
}, {
'BACKEND': 'django.template.backends'
'.django.DjangoTemplates',
'APP_DIRS': True,
}]
![Page 35: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/35.jpg)
Globals
35
# project/jinja2.py
from django.core.urlresolvers import reverse
env.globals.update({
'url': reverse,
})
# templates/header.html
{{ url('account_login') }}
![Page 36: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/36.jpg)
Filters
36
# project/jinja2.py
from urllib.parse import quote
env.filters.update({
'urlquote': quote,
})
# templates/header.html
?next={{ request.get_full_path() | urlquote }}
![Page 37: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/37.jpg)
Tests
37
# project/jinja2.py
from django.utils.timezone import is_aware
env.tests.update({
'aware': is_aware,
})
# templates/datetime.html
{% if at is aware %}{{ at.tzname() }}{% endif %}
![Page 38: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/38.jpg)
Extensions
38
# project/jinja2.py
options.setdefault('extensions', []).extend([
'jinja2.ext.i18n',
])
# or, alternatively:
env.add_extension('jinja2.ext.i18n')
# templates/header.html
{{ gettext("Log in") }}
![Page 39: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/39.jpg)
Jinja2 tips
39
You can go back to sleep — the slides will be online.
![Page 40: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/40.jpg)
Calling methods
40
# Django templates
{{ qotd }}
# Jinja2
{{ qotd() }}
![Page 41: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/41.jpg)
Inserting the CSRF token in a form
41
# Django templates
{% csrf_token %}
# Jinja2
{{ csrf_input }}
# Both
<input type="hidden"
name="csrfmiddlewaretoken"
value="{{ csrf_token }}" />
![Page 42: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/42.jpg)
Replacing a context processor
42
# project/jinja2.py
from django.contrib.messages import get_messages
env.globals.update({
'get_messages': get_messages,
})
![Page 43: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/43.jpg)
Replacing a context processor
43
# templates/header.html
{% for message in get_messages(request) %}
<div>{{ message }}</div>
{% endfor %}
![Page 44: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/44.jpg)
Replacing a context processor - alternative
44
# project/jinja2.py
from django.contrib.messages import get_messages
@jinja2.contextfunction
def _get_messages(context):
return get_messages(context['request'])
env.globals.update({
'get_messages': _get_messages,
})
![Page 45: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/45.jpg)
Replacing a context processor - alternative
45
# templates/header.html
{% for message in get_messages() %}
<div>{{ message }}</div>
{% endfor %}
![Page 46: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/46.jpg)
Replacing a template tag
46
# spam/templatetags.py
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def eat_spam(context, arg1, arg2):
# ...
return html
![Page 47: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/47.jpg)
Replacing a template tag
47
# templates/spam.html
{% load spam %}
{% eat_spam arg1 arg2 %}
![Page 48: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/48.jpg)
Replacing a template tag
48
# spam/jinja2.py
@jinja2.contextfunction
def eat_spam(context, arg1, arg2):
# ...
return html
# and register it in env.globals as shown above.
![Page 49: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/49.jpg)
Replacing a template tag
49
# templates/spam.html
{{ eat_spam(arg1, arg2) }}
![Page 50: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/50.jpg)
Most extensions only add globals
50
# eat/jinja2.py
class EatExtension(Extension):
def __init__(self, env):
env.globals['eat'] = {'spam': eat_spam}
# templates/eat.html
{{ eat.spam() }}
![Page 51: Django - Amazon S3 · PDF fileDjango ! Jinja2 Aymeric Augustin DjangoCong 2016 Jardin des Plantes, Avranches, 9 avril 2016 "](https://reader031.vdocuments.us/reader031/viewer/2022030509/5ab8381d7f8b9a28468c9699/html5/thumbnails/51.jpg)
Questions?
Thank you!
Estuaire de la SĂ©e, Avranches, 9 avril 2016