Django template 2.0 - 草稿
模板标签除了几个常用的,还真心没有仔细了解一下,看到2.0发布后,翻译学习一下。
本文尽量忠实原著,毕竟大神的东西不好亵渎。翻译中我尽量加入自己做项目时候经验,不至于翻译出来不是人类能读的。
一、模板介绍
作为鼎鼎大名的网络框架,Django不能很方便的动态生成HTML,它还好意思出门?最普通的方式就是依靠模板来动态生成。模板主要包括两个内容,一是包含了HTML输出的静态部分,二是怎么样插入动态内容的语法。在教程的第三部分中有一个例子就是用模板生成HTML网页的,有兴趣可以去参考一下。
一个Django 工程一般配置一个或者几个模板引擎,如果你不用模板,当然可以没有。Django自带自己独创的叫DTL的引擎,作为自己模板系统的后端。当然也支持流行的Jinja2引擎。如果你要用其他第三方的引擎,稍加配置后端也支持。
无论那种后端引擎,Django提供了一套标准的API来加载和渲染模板。所谓的加载包括两步,首先找到你指定的模板,然后预处理一下,一般就是编译一下放到内存里备用。所谓的渲染也包括两步,首先把环境变量的数据插入到模板中,然后返回一个结果字符串。
DTL是Django自己的模板系统,在1.8版本以前它仅仅是可选的。以后就默认内置了。Django的开发大神们相当的看好它,可以秒杀其他模板语言。大神这么推崇的模板,如果你没有特别理由,建议用DTL吧。特别是你想开发一个可以随时加入插件的应用并且要发布他的时候。Django自带的像django.contrib.admin的管理后台就是用的DTL 模板。
历史原因,模板引擎和模板语言都在django.template的模块中
警告!
模板系统对恶意模板没有反制措施。所以网站不要允许用户提供自己的模板,恶意的用户有可能会实施XSS攻击,获取模板中的隐私数据
二、对模板引擎的支持
2.1模板引擎的设置
模板引擎在TEMPLATES设置中配置。对每个引擎的配置就是一个字典。默认是空的。如果你用startproject命令来生成你的工程,在setting.py中会默认提供一点有用的配置。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
# ... some options here ...
},
},
]
后端这个键值是个python路径,它指向了一个模板引擎的类,这个类实现了模本后端的API。自带的后端引擎类是django.template.backend.django.DjangoTemplate和django.template.bakend.jinja2.Jinja2
一般来说,引擎是从文件中载入模板,所以顶级配置中为每个引擎提供了两个通用设置选项
DIRS定义了引擎搜索模板源文件的一系列文件夹。搜索的时候是按照你提供的文件夹的顺序来搜索的。
APP_DIRS是告诉引擎你要在安装的应用中搜索模板。每个后端为应用存储模板的下层文件夹提供了通用的名字。
OPTIONS。特殊情况下,你可以为相同的后端用不同的选项值来配置不同的后端实例。这种情况下,你要为每个引擎提供独特的名字。OPTIONS 就是设置后端特殊值的地方
2.2模板的使用
django.template.loader模块里有两个函数来加载模板
get_template(template_name, using=None)
这个函数用指定的模板名字来加载模本,返回一个模板对象
不同的后端加载模板后返回的模板对象是不同的,每个后端都有自己的模板类。
get_template()会按顺序尝试模板引擎,直到成功。注:引擎是自带的不会抛出异常。如果模板没有找到就抛出TemplateDoesNotExist的异常,如果找到模板,但是模板里面有语法错误,就抛出TemplateSyntaxError的异常。
怎么搜索模板以及怎么加载模板?每个引擎后端不同,方式也不同,相同的引擎后端因为配置不同,也会有差别。
如果你想限制在搜索某个引擎,你可以给引擎的NAME变量赋值
select_template(template_name_list, using=None)
select_template() 和get_template()类似,不同之处在于它的参数是一个模板名字的列表。这个方法蒋按顺序搜索每一个名字,搜索到一个符合就停止,返回模板对象。
如果加载模板失败,会抛出下面两个异常,这两个异常实在django.temolate定义好的。
exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)
没有找到匹配的模板会抛出这个异常。在调试页面它会用下面这些参数来填充模板
参数 backend
产生这个异常的模板后端实例。实际就是那个引擎
参数tried
在寻找模板的时候都寻找了那些目录。调试页面会以tuple的形式展示出来,这个tuple包含原始的文件目录和状态。 (origin, status),origin是一个原始样子的对象,status是一个字符串,内容找不到模板的原因
参数chain
加载模板时一系列中间TemplateDoesNotExist异常,一般发生在用多个引擎加载模板的时候,如在get_template方法中
exception TemplateSyntaxError(msg)
This exception is raised when a template was found but contains errors.
Template objects returned by get_template() and select_template() must provide a render() method with the following signature:
Template.render(context=None, request=None)¶
Renders this template with a given context.
If context is provided, it must be a dict. If it isn’t provided, the engine will render the template with an empty context.
If request is provided, it must be an HttpRequest. Then the engine must make it, as well as the CSRF token, available in the template. How this is achieved is up to each backend.
Here’s an example of the search algorithm. For this example the TEMPLATES setting is:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/html/example.com',
'/home/html/default',
],
},
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [
'/home/html/jinja2',
],
},
]
If you call get_template('story_detail.html'), here are the files Django will look for, in order:
/home/html/example.com/story_detail.html ('django' engine)
/home/html/default/story_detail.html ('django' engine)
/home/html/jinja2/story_detail.html ('jinja2' engine)
If you call select_template(['story_253_detail.html', 'story_detail.html']), here’s what Django will look for:
/home/html/example.com/story_253_detail.html ('django' engine)
/home/html/default/story_253_detail.html ('django' engine)
/home/html/jinja2/story_253_detail.html ('jinja2' engine)
/home/html/example.com/story_detail.html ('django' engine)
/home/html/default/story_detail.html ('django' engine)
/home/html/jinja2/story_detail.html ('jinja2' engine)
When Django finds a template that exists, it stops looking.
Tip
You can use select_template() for flexible template loading. For example, if you’ve written a news story and want some stories to have custom templates, use something like select_template(['story_%s_detail.html' % story.id, 'story_detail.html']). That’ll allow you to use a custom template for an individual story, with a fallback template for stories that don’t have custom templates.
It’s possible – and preferable – to organize templates in subdirectories inside each directory containing templates. The convention is to make a subdirectory for each Django app, with subdirectories within those subdirectories as needed.
Do this for your own sanity. Storing all templates in the root level of a single directory gets messy.
To load a template that’s within a subdirectory, just use a slash, like so:
get_template('news/story_detail.html')
Using the same TEMPLATES option as above, this will attempt to load the following templates:
/home/html/example.com/news/story_detail.html ('django' engine)
/home/html/default/news/story_detail.html ('django' engine)
/home/html/jinja2/news/story_detail.html ('jinja2' engine)
In addition, to cut down on the repetitive nature of loading and rendering templates, Django provides a shortcut function which automates the process.
render_to_string(template_name, context=None, request=None, using=None)[source]¶
render_to_string() loads a template like get_template() and calls its render() method immediately. It takes the following arguments.
template_name
The name of the template to load and render. If it’s a list of template names, Django uses select_template() instead of get_template() to find the template.
context
A dict to be used as the template’s context for rendering.
request
An optional HttpRequest that will be available during the template’s rendering process.
using
An optional template engine NAME. The search for the template will be restricted to that engine.
Usage example:
from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', {'foo': 'bar'})
See also the render() shortcut which calls render_to_string() and feeds the result into an HttpResponse suitable for returning from a view.
Finally, you can use configured engines directly:
engines¶
Template engines are available in django.template.engines:
from django.template import engines
django_engine = engines['django']
template = django_engine.from_string("Hello {{ name }}!")
The lookup key — 'django' in this example — is the engine’s NAME.
Built-in backends¶
class DjangoTemplates[source]¶
Set BACKEND to 'django.template.backends.django.DjangoTemplates' to configure a Django template engine.
When APP_DIRS is True, DjangoTemplates engines look for templates in the templates subdirectory of installed applications. This generic name was kept for backwards-compatibility.
DjangoTemplates engines accept the following OPTIONS:
'autoescape': a boolean that controls whether HTML autoescaping is enabled.
It defaults to True.
Warning
Only set it to False if you’re rendering non-HTML templates!
'context_processors': a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.
It defaults to an empty list.
See RequestContext for more information.
'debug': a boolean that turns on/off template debug mode. If it is True, the fancy error page will display a detailed report for any exception raised during template rendering. This report contains the relevant snippet of the template with the appropriate line highlighted.
It defaults to the value of the DEBUG setting.
'loaders': a list of dotted Python paths to template loader classes. Each Loader class knows how to import templates from a particular source. Optionally, a tuple can be used instead of a string. The first item in the tuple should be the Loader class name, and subsequent items are passed to the Loader during initialization.
The default depends on the values of DIRS and APP_DIRS.
See Loader types for details.
'string_if_invalid': the output, as a string, that the template system should use for invalid (e.g. misspelled) variables.
It defaults to an empty string.
See How invalid variables are handled for details.
'file_charset': the charset used to read template files on disk.
It defaults to the value of FILE_CHARSET.
'libraries': A dictionary of labels and dotted Python paths of template tag modules to register with the template engine. This can be used to add new libraries or provide alternate labels for existing ones. For example:
OPTIONS={
'libraries': {
'myapp_tags': 'path.to.myapp.tags',
'admin.urls': 'django.contrib.admin.templatetags.admin_urls',
},
}
Libraries can be loaded by passing the corresponding dictionary key to the {% load %} tag.
'builtins': A list of dotted Python paths of template tag modules to add to built-ins. For example:
OPTIONS={
'builtins': ['myapp.builtins'],
}
Tags and filters from built-in libraries can be used without first calling the {% load %} tag.
class Jinja2[source]¶
Requires Jinja2 to be installed:
$ pip install Jinja2
Set BACKEND to 'django.template.backends.jinja2.Jinja2' to configure a Jinja2 engine.
When APP_DIRS is True, Jinja2 engines look for templates in the jinja2 subdirectory of installed applications.
The most important entry in OPTIONS is 'environment'. It’s a dotted Python path to a callable returning a Jinja2 environment. It defaults to 'jinja2.Environment'. Django invokes that callable and passes other options as keyword arguments. Furthermore, Django adds defaults that differ from Jinja2’s for a few options:
'autoescape': True
'loader': a loader configured for DIRS and APP_DIRS
'auto_reload': settings.DEBUG
'undefined': DebugUndefined if settings.DEBUG else Undefined
Jinja2 engines also accept the following OPTIONS:
'context_processors': a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.
It defaults to an empty list.
Using context processors with Jinja2 templates is discouraged.
Context processors are useful with Django templates because Django templates don’t support calling functions with arguments. Since Jinja2 doesn’t have that limitation, it’s recommended to put the function that you would use as a context processor in the global variables available to the template using jinja2.Environment as described below. You can then call that function in the template:
{{ function(request) }}
Some Django templates context processors return a fixed value. For Jinja2 templates, this layer of indirection isn’t necessary since you can add constants directly in jinja2.Environment.
The original use case for adding context processors for Jinja2 involved:
Making an expensive computation that depends on the request.
Needing the result in every template.
Using the result multiple times in each template.
Unless all of these conditions are met, passing a function to the template is simpler and more in line with the design of Jinja2.
New in Django 1.11:
The 'context_processors' option was added.
The default configuration is purposefully kept to a minimum. If a template is rendered with a request (e.g. when using render()), the Jinja2 backend adds the globals request, csrf_input, and csrf_token to the context. Apart from that, this backend doesn’t create a Django-flavored environment. It doesn’t know about Django filters and tags. In order to use Django-specific APIs, you must configure them into the environment.
For example, you can create myproject/jinja2.py with this content:
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
and set the 'environment' option to 'myproject.jinja2.environment'.
Then you could use the following constructs in Jinja2 templates:
<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">
<a href="{{ url('admin:index') }}">Administration</a>
The concepts of tags and filters exist both in the Django template language and in Jinja2 but they’re used differently. Since Jinja2 supports passing arguments to callables in templates, many features that require a template tag or filter in Django templates can be achieved simply by calling a function in Jinja2 templates, as shown in the example above. Jinja2’s global namespace removes the need for template context processors. The Django template language doesn’t have an equivalent of Jinja2 tests.
Custom backends¶
Here’s how to implement a custom template backend in order to use another template system. A template backend is a class that inherits django.template.backends.base.BaseEngine. It must implement get_template() and optionally from_string(). Here’s an example for a fictional foobar template library:
from django.template import TemplateDoesNotExist, TemplateSyntaxError
from django.template.backends.base import BaseEngine
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
import foobar
class FooBar(BaseEngine):
# Name of the subdirectory containing the templates for this engine
# inside an installed application.
app_dirname = 'foobar'
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
super().__init__(params)
self.engine = foobar.Engine(**options)
def from_string(self, template_code):
try:
return Template(self.engine.from_string(template_code))
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
def get_template(self, template_name):
try:
return Template(self.engine.get_template(template_name))
except foobar.TemplateNotFound as exc:
raise TemplateDoesNotExist(exc.args, backend=self)
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
class Template:
def __init__(self, template):
self.template = template
def render(self, context=None, request=None):
if context is None:
context = {}
if request is not None:
context['request'] = request
context['csrf_input'] = csrf_input_lazy(request)
context['csrf_token'] = csrf_token_lazy(request)
return self.template.render(context)
See DEP 182 for more information.
Debug integration for custom engines¶
The Django debug page has hooks to provide detailed information when a template error arises. Custom template engines can use these hooks to enhance the traceback information that appears to users. The following hooks are available:
Template postmortem¶
The postmortem appears when TemplateDoesNotExist is raised. It lists the template engines and loaders that were used when trying to find a given template. For example, if two Django engines are configured, the postmortem will appear like:
../../_images/postmortem.png
Custom engines can populate the postmortem by passing the backend and tried arguments when raising TemplateDoesNotExist. Backends that use the postmortem should specify an origin on the template object.
Contextual line information¶
If an error happens during template parsing or rendering, Django can display the line the error happened on. For example:
../../_images/template-lines.png
Custom engines can populate this information by setting a template_debug attribute on exceptions raised during parsing and rendering. This attribute is a dict with the following values:
'name': The name of the template in which the exception occurred.
'message': The exception message.
'source_lines': The lines before, after, and including the line the exception occurred on. This is for context, so it shouldn’t contain more than 20 lines or so.
'line': The line number on which the exception occurred.
'before': The content on the error line before the token that raised the error.
'during': The token that raised the error.
'after': The content on the error line after the token that raised the error.
'total': The number of lines in source_lines.
'top': The line number where source_lines starts.
'bottom': The line number where source_lines ends.
Given the above template error, template_debug would look like:
{
'name': '/path/to/template.html',
'message': "Invalid block tag: 'syntax'",
'source_lines': [
(1, 'some\n'),
(2, 'lines\n'),
(3, 'before\n'),
(4, 'Hello {% syntax error %} {{ world }}\n'),
(5, 'some\n'),
(6, 'lines\n'),
(7, 'after\n'),
(8, ''),
],
'line': 4,
'before': 'Hello ',
'during': '{% syntax error %}',
'after': ' {{ world }}\n',
'total': 9,
'bottom': 9,
'top': 1,
}
Origin API and 3rd-party integration¶
Django templates have an Origin object available through the template.origin attribute. This enables debug information to be displayed in the template postmortem, as well as in 3rd-party libraries, like the Django Debug Toolbar.
Custom engines can provide their own template.origin information by creating an object that specifies the following attributes:
'name': The full path to the template.
'template_name': The relative path to the template as passed into the the template loading methods.
'loader_name': An optional string identifying the function or class used to load the template, e.g. django.template.loaders.filesystem.Loader.
The Django template language¶
Syntax¶
About this section
This is an overview of the Django template language’s syntax. For details see the language syntax reference.
A Django template is simply a text document or a Python string marked-up using the Django template language. Some constructs are recognized and interpreted by the template engine. The main ones are variables and tags.
A template is rendered with a context. Rendering replaces variables with their values, which are looked up in the context, and executes tags. Everything else is output as is.
The syntax of the Django template language involves four constructs.
Variables¶
A variable outputs a value from the context, which is a dict-like object mapping keys to values.
Variables are surrounded by {{ and }} like this:
My first name is {{ first_name }}. My last name is {{ last_name }}.
With a context of {'first_name': 'John', 'last_name': 'Doe'}, this template renders to:
My first name is John. My last name is Doe.
Dictionary lookup, attribute lookup and list-index lookups are implemented with a dot notation:
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
If a variable resolves to a callable, the template system will call it with no arguments and use its result instead of the callable.
Tags¶
Tags provide arbitrary logic in the rendering process.
This definition is deliberately vague. For example, a tag can output content, serve as a control structure e.g. an “if” statement or a “for” loop, grab content from a database, or even enable access to other template tags.
Tags are surrounded by {% and %} like this:
{% csrf_token %}
Most tags accept arguments:
{% cycle 'odd' 'even' %}
Some tags require beginning and ending tags:
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
A reference of built-in tags is available as well as instructions for writing custom tags.
Filters¶
Filters transform the values of variables and tag arguments.
They look like this:
{{ django|title }}
With a context of {'django': 'the web framework for perfectionists with deadlines'}, this template renders to:
The Web Framework For Perfectionists With Deadlines
Some filters take an argument:
{{ my_date|date:"Y-m-d" }}
A reference of built-in filters is available as well as instructions for writing custom filters.
Comments¶
Comments look like this:
{# this won't be rendered #}
A {% comment %} tag provides multi-line comments.
Components¶
About this section
This is an overview of the Django template language’s APIs. For details see the API reference.
Engine¶
django.template.Engine encapsulates an instance of the Django template system. The main reason for instantiating an Engine directly is to use the Django template language outside of a Django project.
django.template.backends.django.DjangoTemplates is a thin wrapper adapting django.template.Engine to Django’s template backend API.
Template¶
django.template.Template represents a compiled template. Templates are obtained with Engine.get_template() or Engine.from_string()
Likewise django.template.backends.django.Template is a thin wrapper adapting django.template.Template to the common template API.
Context¶
django.template.Context holds some metadata in addition to the context data. It is passed to Template.render() for rendering a template.
django.template.RequestContext is a subclass of Context that stores the current HttpRequest and runs template context processors.
The common API doesn’t have an equivalent concept. Context data is passed in a plain dict and the current HttpRequest is passed separately if needed.
Loaders¶
Template loaders are responsible for locating templates, loading them, and returning Template objects.
Django provides several built-in template loaders and supports custom template loaders.
Context processors¶
Context processors are functions that receive the current HttpRequest as an argument and return a dict of data to be added to the rendering context.
Their main use is to add common data shared by all templates to the context without repeating code in every view.
Django provides many built-in context processors. Implementing a custom context processor is as simple as defining a function.
Form Assets (the Media class)Class-based views
BACK TO TOP
Additional Information
Search:
Search 2.0 documentation
搜索
Support Django!
Support Django!
Chris Cogdon donated to the Django Software Foundation to support Django development. Donate today!
Contents
Templates
Support for template engines
Configuration
Usage
Built-in backends
Custom backends
Debug integration for custom engines
Template postmortem
Contextual line information
Origin API and 3rd-party integration
The Django template language
Syntax
Variables
Tags
Filters
Comments
Components
Engine
Template
Context
Loaders
Context processors
Browse
Prev: Form Assets (the Media class)
Next: Class-based views
Table of contents
General Index
Python Module Index
You are here:
Django 2.0 documentation
Using Django
Templates
Getting help
FAQ
Try the FAQ — it's got answers to many common questions.
Index, Module Index, or Table of Contents
Handy when looking for specific information.
django-users mailing list
Search for information in the archives of the django-users mailing list, or post a question.
#django IRC channel
Ask a question in the #django IRC channel, or search the IRC logs to see if it’s been asked before.
Ticket tracker
Report bugs with Django or Django documentation in our ticket tracker.
Download:
Offline (Django 2.0): HTML | PDF | ePub
Provided by Read the Docs.
Django Links
Learn More
About Django
Getting Started with Django
Team Organization
Django Software Foundation
Code of Conduct
Diversity Statement
Get Involved
Join a Group
Contribute to Django
Submit a Bug
Report a Security Issue
Follow Us
GitHub
News RSS
Django Users Mailing List
Django
Hosting by
Rackspace
Design by
Threespot
&
© 2005-2018 Django Software Foundation and individual contributors. Django is a registered trademark of the Django Software Foundation.