Django模板
配置
在settings.py中配置,BACKEND
表示要使用那种模板引擎;DIRS
表示template的目录(可以是多个);APP_DIRS
表示是否使用app中的template目录(即形如这样的app/templates/
);OPTIONS
是DjangoTemplates
的一些参数,默认即可。
比如:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, "templates"),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
要是想使用Jinja2:把BACKEND
改为django.template.backends.jinja2.Jinja2
即可。
当使用多个模板引擎时,django会按照列表的顺序找到html文件,然后渲染。需要注意的是:django查找到任何一个匹配的模板后便停止搜寻,所以这是个类似url搜索的短路操作!
使用
一般来说我们可以使用django.shortcuts.render
指定template文件,然后进行渲染:
from django.shortcuts import render
def index(request):
return render(request, "app01/index.html")
render背后其实是这样的:
from django.template import loader
from django.http import HttpResponse
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
render的参数
- request是一个HttpRequest对象
- template_name:一般来说一个HTML文件,其路径需要在settings中配置好
- context:需要传一个字典,里面的键值对可以在html页面中供模板引擎使用
- content_type:内容类型
模板语言
django作为一个重型web框架,自然少不了模板语言。这主要是用于动态渲染HTML页面的。
变量
使用两个大括号获取,对于对象的属性等数据可以在其基础上是用.
获取。对于Model对象,可以通过.
来取值,也可以使用.xxx_set
的方式进行反向查找,但查找操作不太适合在模板中完成。
比如:
# views.py
from django.shortcuts import render
def index(request):
data = {
"username": "lczmx",
"age": 22,
}
msg_list = ["1234", "abcd", "6666"]
print(request.session.get(""))
return render(request, "app01/index.html", {"data": data, "msg_list": msg_list})
<!-- app01/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
<p>{{ data.username }}</p>
<p>{{ data.age }}</p>
<p>{{ msg_list.0 }}</p>
</body>
</html>
标签
django模板引擎的标签就相当于python的代码块,以{% %}
的定义。
django已经为我们贴心地内置了一下标签 :
标签 | 作用 |
---|---|
autoescape | 自动转义开关 |
block | 块引用 |
comment | 注释 |
csrf_token | CSRF令牌 |
cycle | 循环对象的值 |
debug | 调试模式 |
extends | 继承模版 |
filter | 过滤功能 |
firstof | 输出第一个不为False的参数 |
for | 循环对象 |
for … empty | 带empty说明的循环 |
if | 条件判断 |
ifchanged | 如果有变化,则.. |
include | 导入子模版的内容 |
load | 加载标签和过滤器 |
lorem | 生成无用的废话 |
now | 当前时间 |
regroup | 根据对象重组集合 |
resetcycle | 重置循环 |
spaceless | 去除空白 |
templatetag | 转义模版标签符号 |
url | 获取url字符串 |
verbatim | 禁用模版引擎 |
widthratio | 宽度比例 |
with | 上下文变量管理器 |
对于使用方法,见django tag
as语法的使用
使用as语法可以将返回值赋值给一个变量,如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
{% url "app01:index" as index_url %}
<a href="{{ index_url }}">index page</a>
</body>
</html>
模板继承:
extends与block结合,可以让你的一些模板继承其他模板,从而极大地减少代码的复用程度。
模板继承允许你建立一个基本的“骨架”模板,它包含了你网站的所有常用元素,并定义了子模板可以覆盖的 块。
我们先看一个例子,看看模板继承:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
这个模板,我们称之为base.html
,它定义了一个 HTML 骨架文档,你可以用它来制作一个两栏式页面。“子”模板的工作是用内容填充空块。
在这个例子中,block 标签定义了三个块,子模板可以填入其中。block 标签所做的就是告诉模板引擎,子模板可以覆盖模板的这些部分。
一个子模板可能是这样的:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
extends 标签是这里的关键。它告诉模板引擎,这个模板“扩展”了另一个模板。当模板系统执行这个模板时,首先要找到父模板——在本例中是“base.html”。
这时,模板引擎会注意到 base.html 中的三个 block 标签,然后用子模板的内容替换这些块。根据 blog_entries 的值,输出可能是这样的:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>My amazing blog</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
<div id="content">
<h2>Entry one</h2>
<p>This is my first entry.</p>
<h2>Entry two</h2>
<p>This is my second entry.</p>
</div>
</body>
</html>
请注意,由于子模板没有定义 sidebar
块,所以使用父模板的值来代替。父模板中 {% block %} 标签中的内容总是被用作后备。
你可以根据需要使用任意层次的继承。一种常见的使用继承的方式是像以下的三层继承:
- 创建一个 base.html 模板,以保持你网站的主要外观和风格。
- 为你网站的每个“部分”创建一个 base_SECTIONNAME.html 模板。
例如,base_news.html、base_sports.html。这些模板都是对 base.html 的扩展,并包括特定部分的样式/设计。 - 为每种类型的页面创建单独的模板
如新闻文章或博客条目。这些模板扩展了相应的部分模板。
下面是一些关于继承工作的技巧:
- 如果你在模板中使用 {% extends %},它必须是该模板中的第一个模板标签。否则,模板继承将无法使用。
- 基础模板中的 {% block %} 标签越多越好。记住,子模板不需要定义所有的父块,所以你可以在一些块中填入合理的默认值,然后只定义以后需要的块。钩子多比钩子少好。
- 如果你发现自己的内容在多个模板中重复,可能意味着你应该把这些内容移到父模板中的 {% block %}。
- 如果你需要从父模板中获取块的内容,{{ block.super }} 变量就可以做到这一点。如果你想添加到父模板的内容中,而不是完全覆盖它,这很有用。使用 {{ block.super }} 插入的数据不会被自动转义,因为如果需要的话,它已经在父模板中被转义了。
- 通过使用与继承模板相同的模板名称,{% extends %} 可以在覆盖模板的同时继承它。结合 {{ block.super }},这可以成为一种强大的小规模定制方式。 比如官方给出的这个例子:扩展复写模板。
在 {% block %}
之外使用模板标签 as
语法创建的变量不能在块中使用。例如,这个模板不会呈现任何东西:
{% translate "Title" as title %}
{% block content %}{{ title }}{% endblock %}
为了增加可读性,你可以给你的 {% endblock %}
标签 起一个 名字。例如:
{% block content %}
...
{% endblock content %
}
在较大的模板中,这种技术可以帮助你看到哪些 {% block %}
标签正在被关闭。
最后,请注意,你不能在同一个模板中定义多个同名的 block 标签。
过滤器
过滤器就相当于python语法中的函数,其使用语法是:{{ 变量 | 过滤器:参数 }}
,其中,对于没有参数的过滤器来说,:参数
这部分省略。
内置过滤器
过滤器 | 说明 |
---|---|
add | 加法 |
addslashes | 添加斜杠 |
capfirst | 首字母大写 |
center | 文本居中 |
cut | 切除字符 |
date | 日期格式化 |
default | 设置默认值 |
default_if_none | 为None设置默认值 |
dictsort | 字典排序 |
dictsortreversed | 字典反向排序 |
divisibleby | 整除判断 |
escape | 转义 |
escapejs | 转义js代码 |
filesizeformat | 文件尺寸人性化显示 |
first | 第一个元素 |
floatformat | 浮点数格式化 |
force_escape | 强制立刻转义 |
get_digit | 获取数字 |
iriencode | 转换IRI |
join | 字符列表链接 |
json_script | 生成script标签,带json数据 |
last | 最后一个 |
length | 长度 |
length_is | 长度等于 |
linebreaks | 行转换 |
linebreaksbr | 行转换 |
linenumbers | 行号 |
ljust | 左对齐 |
lower | 小写 |
make_list | 分割成字符列表 |
phone2numeric | 电话号码 |
pluralize | 复数形式 |
pprint | 调试 |
random | 随机获取 |
rjust | 右对齐 |
safe | 安全确认 |
safeseq | 列表安全确认 |
slice | 切片 |
slugify | 转换成ASCII |
stringformat | 字符串格式化 |
striptags | 去除HTML中的标签 |
time | 时间格式化 |
timesince | 从何时开始 |
timeuntil | 到何时多久 |
title | 所有单词首字母大写 |
truncatechars | 截断字符 |
truncatechars_html | 截断字符 |
truncatewords | 截断单词 |
truncatewords_html | 截断单词 |
unordered_list | 无序列表 |
upper | 大写 |
urlencode | 转义url |
urlize | url转成可点击的链接 |
urlizetrunc | urlize的截断方式 |
wordcount | 单词计数 |
wordwrap | 单词包裹 |
yesno | 将True,False和None,映射成字符串‘yes’,‘no’,‘maybe’ |
一般的使用例子,以add为例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
<p>你明年的年龄是{{ data.age | add:1 }}</p>
</body>
</html>
其他的内置过滤的参考。
关于safe字符串,见:几种safe字符串的方法
自定义标签及过滤器
一般来说,默认的标签和过滤器已经够我们应付简单场景的了,面对复杂的需求的话,我们可以使用自定义标签和过滤器的办法。
自定义标签及过滤器的位置就是 Django 应用内。如果它们关联至某个已存在的应用,在那里将它们打包就很有用;否则,它们能被添加至新应用。当一个 Django 应用被添加至 INSTALLED_APPS,所以其在常规位置定义的标签都可以在模板中自动加载。
自定义标签
- app中创建一个名为templatetags的Python 包
- 在templatetags下创建一个py文件,用于放标签函数
- 创建一个函数
- 使用
django.template.Library
对象的simple_tag
方法装饰,可以指定name参数,表示标签名,空的时候为函数名 - 重启django
- 在template中使用load标签将自定义标签引入
- 以
{% xx %}
的形式使用
例子:
# 第1和第2步省略
# app的目录机构(部分):
# app01
# ├── admin.py
# ├── apps.py
# ├── templatetags
# │ ├── __init__.py
# │ ├── mytags.py
# │ └── __pycache__
# │ ├── __init__.cpython-38.pyc
# │ └── mytags.cpython-38.pyc
# ├── tests.py
# ├── urls.py
# └── views.py
# app01/templatetags/mytags.py
from django import template
# 第4步
register = template.Library()
# 指定name参数为t1,在template中就只能用t1了
@register.simple_tag(name="t1")
def my_tag(x, y, *args):
print(x, y)
print(args)
return "t1"
{# 使用load自定义标签,mytags是py文件,t1是name指定的参数, 若不指定,则为函数名#}
{% load t1 from mytags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
{# 使用t1标签 #}
{% t1 12 234 134 %}
</body>
</html>
自定义过滤器
- app中创建一个名为templatetags的Python 包
- 在templatetags下创建一个py文件,用于放过滤器函数
- 创建一个函数
- 使用
django.template.Library
对象的filter
方法装饰,可以指定name参数,表示过滤器名,空的时候为函数名 - 重启django
- 在template中使用load标签将自定义过滤器引入
- 以
{{ xx | yy:z}}
的形式使用
filter和tag很像,就装饰器、函数参数、模板使用方法有所区别,例子:
# app01/templatetags/myfilter.py
from django import template
register = template.Library()
@register.filter(name="f1")
def my_filter(x, y, z):
print(x, y, z)
return "f1"
{# 使用load自定义过滤器,myfilter是py文件 #}
{% load f1 from myfilter %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
{# 使用f1过滤器 #}
{{ "hello"|f1:123 }}
</body>
</html>
load标签的使用
load是用于加载一个自定义模板标签集。
上面在例子使用了load标签,下面记录一下其语法。
在使用时可以把load类比成python的import
比如现在在templatetags下有两个文件,每个文件中有一个标签或过滤器函数:
# app/templatetags/myfilter.py
from django import template
register = template.Library()
@register.filter(name="f1")
def my_filter(x, y):
print(x, y)
return "f1"
# ########################################################## #
# app/templatetags/myfilter.py
from django import template
register = template.Library()
@register.simple_tag(name="t1")
def my_tag(x, y, *args):
print(x, y)
print(args)
return "t1"
那么就有两种方法加载:
第一种
{# load的是py文件#}
{% load mytags %}
{% load myfilter %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
{# 直接使用 #}
{% t1 12 234 134 %}
{{ "hello"|f1:123 }}
</body>
</html>
方法二:
此方法可以同时加载多个,以空格隔开,如:{% load f1 f2 from myfliter %}
{#{% load t1 from mytags %}#}
{#{% load f1 from myfilter %}#}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>app01 index</title>
</head>
<body>
{# 使用 #}
{% t1 12 234 134 %}
{{ "hello"|f1:123 }}
</body>
</html>
本文来自博客园,作者:403·Forbidden,转载请注明原文链接:https://www.cnblogs.com/lczmx/p/14938874.html