Two Scoops of Django (1.6)
Templates and Tags
Date: 2014.12.16 Speaker: Apua Last Update: 2014.12.16
Concept
- Explicit is better than Implicit
- Flat is better than Nested
- Minimalist Approach
- Limit Processing
Templates
Settings
TEMPLATE_DIRS = (os.path.join(BASE_DIR, "template"),)
INSTALLED_APPS = ('myproject.polls', 'myproject.music')
TEMPLATE_LOADERS = (
('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)),
)
Basic
{% extend "base.html" %}
{% block body %}
{{ block.super }}
{{ form_subtitle }}
<form method="post">
{% include form_template %}
</form>
<a href="{% url 'home' %}">Home</a>
{% endblock %}
{# Those are `context` objects #}
Basic Control Flow
{% if display_inbox %}
{% with emails=user.emails.all %}
<p>You have {{ emails|lenght }} email(s)</p>
{% for email in emails %}
<p>{{ email.body }}</p>
{% endfor %}
{% endif %}
Filters and Tags
{# A filter `lower` #}
{% "ABC"|lower %}
{# A tag `autoescape` #}
{% autoescape %}
{{ obj }}
{% endautoescape %}
Notices
- Use named Context objects.
- Don't bother (merged) HTML pretty.
- Recommend 2-tier or 3-tier architecture.
- Avoid unnecessary aggregation and
condition filtering in Templates. - Use CSS for styling.
Customize Tags and Filters
Location
myapp/
|-- __init__.py
|-- admin.py
|-- models.py
|-- templatetags
| `-- myapp_tags.py
|-- tests.py
`-- views.py
Naming Tag Libraries
Recommand:
Warning:
Don't name template tag libraries with the same name as app .
Don't rely on IDE to determine the name.
<app_name>_tags.py
Load
{% extends "base.html" %}
{% load myapp_tags %}
Customize Filters
# myapp/templatetags/myapp_tags.py
from django import template
register = template.Library()
@register.filter
def myfilter(val, arg): # limit one or two arguments
pass
return "altered_string"
{% extends "base.html" %}
{% load myapp_tags %}
{% val|myfilter:arg %}
Customize Tags
# myapp/templatetags/myapp_tags.py
from django import template
register = template.Library()
@register.tag
def mytag(parser, token, *args, **kwargs):
pass
return template.Node()
{% extends "base.html" %}
{% load myapp_tags %}
{% mytag arg0 arg1 kwarg0="val0"|lower kwarg1=var %}
This part would be token.
{% endmytag %}
When to Write
Filters and Tags
Filters:
Modifying the presentation of data.
It can be readily reused in REST APIs
and other output formats
Tags:
Only responsible for rendering of HTML.
Bottleneck
Correct complex implied queries
in templates.
{% comment %}
`user_list` generated via
User.object.all() or User.selet_related("flavors")
{% endcomment %}
{% for user in user_list %}
{{ user.name }} <br />
{{ user.flavor.title }} <br />
{{ user.flavor.scoops_remaining }} <br />
{% endfor %}
Avoid hidden CPU load and
REST API calls in templates.
Consider caching the loaded templates if custom tags load lots of templates.
Ends and Odds
Don't replace Django template engine.
See chapter 16: Tradeoffs of Replacing Core Components
Debugging complex templates.
# setttings/local.py
TEMPLATE_STRING_IF_INVALID = "INVALID EXPRESSION: %s"
Serve error pages
entirely self-contained static.
Filter are easy to test.
Tags are harder to debug.
Liberal use of log statements and tests are helpful.
See chapter 20: Testing Stinks and Is a Waste of Money!
Filters can be reusable.
# from django.template.defaultfilters import (slugify,
# remove_tags)
from django.utils.text import slugify
from django.utils.html.remove_tags
Tags make code reuse harder.
But don't create anti-pattern for DRY.
# Anti-pattern
from django import template
template.add_to_builtins("myapp.templatetags.myapp_tags")
Two Scoops of Django
By Apua A.Aa
Two Scoops of Django
- 1,202