Django开发-模板系统

第1章 常用语法

两种特殊符号:

{{ }}:变量相关
{% %}:逻辑相关

1.1 变量

在Django的模板语言中使用{{ 变量名 }}定义变量。

变量的命名包括任何字母数字以及下划线 (“_”)的组合,变量名称中不能有空格或标点符号。点(”.”)在模板语言中有特殊的含义,当模版系统遇到点(“.”)将以下面的顺序查询:

  1. 字典查询(Dictionary lookup)
  2. 属性或方法查询(Attribute or method lookup)
  3. 数字索引查询(Numeric index lookup)

注意:如果计算结果的值是可调用的,结果将被无参数的调用,调用的结果将成为模版的值;如果使用的变量不存在,模版系统将插入 string_if_invalid 选项的值,它被默认设置为空字符串。

【示例】:view.py中代码:

from django.shortcuts import HttpResponse, render, redirect

def template_test(request):

    file_size = 123456789

    name_list = ['张三', '李四', '王五']
    name_list2 = [['张三0', '李四0', '王五0'], ['张三1', '李四1', '王五1']]
    name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}

    from datetime import datetime, timedelta
    now = datetime.now()
    yesterday = datetime.now()-timedelta(days=1)
    print(now)
    print(yesterday)

    a_html = "<a href='https://www.baidu.com'>我是后端传过来的a标签</a>"
    script_html = "<script>alert('test')</script>"

    c_str = """
        床前明月光 疑是地上霜 举头望明月 低头思故乡
    """
    w_ptr = """
        Bright moonlight shines over my bed, Just like frost covering the land, Raise my head to look at the Moon, Miss my hometown when I look down.
    """

    return render(
        request,
        'template_test.html',
        {
            "file_size": file_size,
            'name_list': name_list,
            'name_list2':name_list2,
            'name_dict': name_dict,
            'now': now,
            'yesterday': yesterday,
            'a_html': a_html,
            'script_html': script_html,
            'c_str': c_str,
            'w_str': w_ptr
        }
    )

模板中支持的写法:

{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}

1.2 Filters(过滤器)

在Django的模板语言中通过使用过滤器来改变变量的显示。过滤器的语法:

{{ value|filter_name:参数 }}

使用管道符”|”来应用过滤器。例如:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值(lower在这里的作用是将文本全都变成小写)。过滤器具有如下特点:

  1. 过滤器支持“链式”操作,即一个过滤器的输出作为另一个过滤器的输入;
  2. 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词;
  3. 过滤器参数包含空格的话必须用引号包裹起来,比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:’, ‘ }}

注意:’|’左右不能存在空格

1.2.1 内置过滤器

1.2.1.1 default

如果一个变量是false或者为空则使用给定的默认值,否则使用变量的值:

{{ value|default:"nothing"}}  # 如果value没有传值或者值为空的话就显示nothing

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是Django模板语言测试的html!</h1>
<p>空值测试:{{ null_char|default:"这是一个空值" }}</p>
</body>
</html>

【运行结果】:

图片[1]|Django开发-模板系统|leon的博客

1.2.1.2 length

返回值的长度,作用于字符串和列表:

{{ value|length }}  # 返回value的长度,如 value=['a','b','c','d']的话就显示4

【示例】:views.py

def template_test(request):
name_list = ['张三', '李四', '王五']
name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
return render(
    request,
    'template_test.html',
    {
        'name_list': name_list,
        'name_dict': name_dict
    }
)

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是Django模板语言测试的html!</h1>
<p>长度测试:{{ name_list|length }}</p>
<p>长度测试:{{ name_dict|length }}</p>
</body>
</html>

【运行结果】:

图片[2]|Django开发-模板系统|leon的博客

1.2.1.3 filesizeformat

将值格式化为一个人类可读的文件尺寸:

{{ value|filesizeformat }}  # 如果value是123456789,输出将会是 117.7 MB

【示例】:views.py

def template_test(request):
    file_size = 123456789
    return render(
        request,
        'template_test.html',
        {
            "file_size": file_size
        }
)

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<h1>这是Django模板语言测试的html!</h1>
<p>文件大小:{{ file_size|filesizeformat }}</p>
</body>
</html>

【运行结果】:

图片[3]|Django开发-模板系统|leon的博客

1.2.1.4 slice

切片:

{{value|slice:"0:-1"}}      # 从第首位到最后一位,不含最后一位

【示例】:views.py

def template_test(request):
name_list = ['张三', '李四', '王五']
name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
return render(
    request,
    'template_test.html',
    {
        'name_list': name_list,
        'name_dict': name_dict
    }
)

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是Django模板语言测试的html!</h1>
<p>切片:{{ name_list|slice:"0:-1" }}</p>
<p>切片:{{ name_dict.name3|slice:"1:2" }}</p>
</body>
</html>

【运行结果】:

图片[4]|Django开发-模板系统|leon的博客

1.2.1.5 date

时间格式化:

{{ value|date:"Y-m-d H:i:s"}}

可用的参数:

格式化字符 描述 示例输出
a ‘a.m.’或’p.m.’ ‘a.m.’
A ‘AM’或’PM’。 ‘AM’
b 3个字母的文字月份,小写。 ‘jan’(一月)
c ISO 8601格式。 2008-01-02T10:30:00.000123+02:00

或2008-01-02T10:30:00.000123

d 有前导零的月份的日子。 ’01’到’31’
D 文字星期,3个字符 “星期五”
e 时区名称可能是任何格式,也可能返回一个空字符串,具体取决于datetime。 ”、’GMT’、’-500’、’US/Eastern’等
f 12小时制时间,如果分钟为0则不显示。 ‘1’,’1:30′
F 文字显示的月份。 ‘一月’
g 12小时格式小时,无前导零。 ‘1’到’12’
G 24小时制小时,无前导零。 ‘0’到’23’
h 12小时制小时,有前导零。 ’01’到’12’
H 24小时制小时,有前导零。 ’00’到’23’
i 分钟。 ’00’到’59’
I 夏令时间,无论是否生效。 ‘1’或’0′
j 没有前导零的月份的日子。 ‘1’到’31’
l 星期几。 ‘星期五’
L 否是一个闰年(布尔值)。 True或False
m 2位数字带前导零的月份。 ’01’到’12’
M 月,文字,3个字母。 “扬”
n 没有前导零的月份。 ‘1’到’12’
N 美联社风格的月份缩写。 ‘Jan.’,’Feb.’,’March’,’May’
o ISO-8601周编号,对应于使用闰年的ISO-8601周数(W)。 ‘1999年’
O 与格林威治时间的差异在几小时内。 ‘+0200’
P 12小时制时间和’a.m’/’p.m’,分钟为零不显示,特殊情况 “午夜”和“中午”。 ‘1 am’,’1:30 pm’ / t3>,’midnight’,’noon’,’12:30 pm’ / T10>
r RFC 5322格式化日期。 ‘Thu, 21 Dec 2000 16:01:07 +0200’
s 带前导零的秒。 ’00’到’59’
S 2个字符的一个月的英文序数后缀。 ‘st’,’nd’,’rd’或’th’
t 给定月份的天数。 28 to 31
T 本机的时区。 ‘EST’,’MDT’
u 微秒。 000000 to 999999
U 自Unix Epoch以来的时间(1970年1月1日00:00:00 UTC)。
w 星期几,数字无前导零。 ‘0’(星期日)至’6’(星期六)
W ISO-8601周数,周数从星期一开始。 1,53
y 2位数字的年份。 ’99’
Y 4位数字带年的年份。 ‘1999年’
z 一年中的日子 0到365
Z 时区偏移量,单位为秒。UTC以西时区的偏移量为负数, UTC以东为正。 -43200到43200

【示例】:views.py

def template_test(request):
    from datetime import datetime
    now = datetime.now()
    print(now)
    return render(
        request,
        'template_test.html',
        {
            'now': now
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是Django模板语言测试的html!</h1>
<p>时间格式化:{{ now|date:"Y-m-d H:i:s" }}</p>
<p>时间格式化:{{ now|date:"a A P" }}</p>
<p>时间格式化:{{ now|date:"c" }}</p>
<p>时间格式化:{{ now|date:"b d D" }}</p>
<p>时间格式化:{{ now|date:"Y-m-d f" }}</p>
<p>时间格式化:{{ now|date:"I L" }}</p>
<p>时间格式化:{{ now|date:"y-n-j G:i l T z" }}</p>
</html>

【运行结果】:

图片[5]|Django开发-模板系统|leon的博客

1.2.1.6 safe

Django的模板中会对HTML标签和JS等语法标签进行自动转义,可以通过过滤器“|safe”的方式禁止Django对标签进行转义。

value = "<a href='#'>点我</a>"
{{ value|safe}}

【示例】:views.py

def template_test(request):
    a_html = "<a href='https://www.baidu.com'>我是后端传过来的a标签</a>"
    script_html = "<script>alert('test')</script>"
    return render(
        request,
        'template_test.html',
        {
            'a_html': a_html,
            'script_html': script_html
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是Django模板语言测试的html!</h1>
<p>a标签:{{ a_html }}</p>
<p>a标签:{{ a_html|safe }}</p>
<p>js标签:{{ script_html }}</p>
<p>js标签:</p>
{{ script_html|safe }}
</html>

【运行结果】:

图片[6]|Django开发-模板系统|leon的博客

1.2.1.7 truncatechars

如果字符串字符多于指定的字符数量则会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。

参数:截断的字符数

{{ value|truncatechars:20}}     # 以字符分隔

1.2.1.8 truncatewords

在一定数量的字后截断字符串。

{{ value|truncatewords:20}}     # 以空格分隔作为一个words

【示例】:views.py

def template_test(request):
    c_str = """
        床前明月光 疑是地上霜 举头望明月 低头思故乡
    """
    w_ptr = """
        Bright moonlight shines over my bed, Just like frost covering the land, Raise my head to look at the Moon, Miss my hometown when I look down.
    """
    return render(
        request,
        'template_test.html',
        {
            'c_str': c_str,
            'w_str': w_ptr
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>大段文本截断:{{ c_str|truncatechars:20 }}</p>
<p>大段文本截断:{{ w_str|truncatewords:20 }}</p>
</html>

【运行结果】:

图片[7]|Django开发-模板系统|leon的博客

1.2.1.9 cut

移除value中所有的与给出的变量相同的字符串:

{{ value|cut:' ' }}  # 如果value为'i love you',那么将输出'iloveyou'

1.2.1.10 join

使用字符串连接列表:例如Python的str.join(list)

【示例】:views.py

def template_test(request):
    c_str = """
        床前明月光 疑是地上霜 举头望明月 低头思故乡
    """
    w_ptr = """
        Bright moonlight shines over my bed, Just like frost covering the land, Raise my head to look at the Moon, Miss my hometown when I look down.
    """
    return render(
        request,
        'template_test.html',
        {
            'c_str': c_str,
            'w_str': w_ptr
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>cut测试:{{ w_str|cut:' ' }}</p>
<p>join测试:{{ c_str|join:"," }}</p>
</html>

【运行结果】:

图片[8]|Django开发-模板系统|leon的博客

1.2.1.11 timesince

将日期格式设为自该日期起的时间(例如,“4天,6小时”)。

采用一个可选参数,它是一个包含用作比较点的日期的变量(不带参数,比较点为现在)。例如:如果blog_date是表示2006年6月1日午夜的日期实例,并且comment_date是2006年6月1日08:00的日期实例,则以下将返回“8小时”:

{{ blog_date|timesince:comment_date }}

分钟是所使用的最小单位,对于相对于比较点的未来的任何日期,将返回“0分钟”。

1.2.1.12 timeuntil

与timesince相似,测量从现在开始直到给定日期或日期时间的时间。 例如:今天是2006年6月1日,而conference_date是2006年6月29日的日期实例,则{{ conference_date | timeuntil }}将返回“4周”。

使用可选参数,它是一个包含用作比较点的日期(而不是现在)的变量。 如果from_date包含2006年6月22日,则以下内容将返回“1周”:

{{ conference_date|timeuntil:from_date }}

【示例】:views.py

def template_test(request):
    from datetime import datetime, timedelta
    now = datetime.now()
    yesterday = datetime.now()-timedelta(days=1)
    print(now)
    print(yesterday)
    return render(
        request,
        'template_test.html',
        {
            'now': now,
            'yesterday': yesterday
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>timesince测试:{{ yesterday|timesince:now }}</p>
<p>timeuntil测试:{{ now|timeuntil:yesterday }}</p>
</html>

【运行结果】:

图片[9]|Django开发-模板系统|leon的博客

1.2.2 自定义filter

自定义过滤器只是带有一个或两个参数的Python函数:

  • 变量(输入)的值:不一定是一个字符串
  • 参数的值:这可以有一个默认值,或完全省略

例如,在过滤器{{var | foo:’bar’}}中,过滤器foo将传递变量var和参数“bar”。

1.2.2.1 自定义filter代码文件摆放位置

app01/
    templatetags/       # 在app01下面新建一个package package
        myfilter.py     # 建一个存放自定义filter的文件

图片[10]|Django开发-模板系统|leon的博客

1.2.2.2 编写自定义filter

from django import template
# 生成一个注册用的实例
register = template.Library()

# 定义并注册一个自定义的filter函数
@register.filter(name="ac")
def add_char(arg):
    return "{} handsome.".format(arg)

# 告诉Django的模板语言现在有一个自定义的filter方法,名字叫as
@register.filter(name="as")
def add_str(arg1,arg2):
    """
    第一个参数永远是管道符前面那个变量
    :param arg1: 管道符前面那个变量
    :param arg2: 冒号后面的变量
    :return:
    """
    return "{} {}.".format(arg1,arg2)

1.2.2.3 使用自定义filter

{# 先导入自定义filter文件 #}
{% load myfilter %}


{# 使用自定义的filter #}
<p>自定义过滤器测试:{{ name_list|ac }}</p>
<p>自定义过滤器测试:{{ name_dict.name2|as:"handsome" }}</p>

【示例】:views.py

def template_test(request):
    name_list = ['张三', '李四', '王五']
    name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
    return render(
        request,
        'template_test.html',
        {
            'name_list': name_list,
            'name_dict': name_dict
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{% load myfilter %}
<p>自定义过滤器测试:{{ name_list|ac }}</p>
<p>自定义过滤器测试:{{ name_dict.name2|as:"handsome" }}</p>
</html>

【运行结果】:

图片[11]|Django开发-模板系统|leon的博客

1.3 Tags

1.3.1 for循环

1.3.1.1 普通for循环

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% endfor %}
</ul>

for循环可用的一些参数:

Variable Description
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环

【示例】:views.py

def template_test(request):
name_list = ['张三', '李四', '王五']
name_list2 = [['张三0', '李四0', '王五0'], ['张三1', '李四1', '王五1']]
    name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
    return render(
        request,
        'template_test.html',
        {
            'name_list': name_list,
            'name_dict': name_dict
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>for单次循环测试</p>
<ul>
    {% for name in name_list %}
        {% if forloop.last %}
            <li class="dsb">{{ forloop.revcounter }}-{{ name }}</li>
        {% else %}
            <li class="{% if forloop.first %}'handsome'{% endif %}">{{ forloop.revcounter }}-{{ name }}</li>
        {% endif %}
    {% endfor %}
</ul>

<p>for双层循环测试</p>
{% for name_outer in name_list2 %}
    {% for name_inner in name_outer %}
        <li>
            {{ forloop.parentloop.counter }}
            {{ forloop.counter }}
            {{ name_inner }}
        </li>
    {% endfor %}
{% endfor %}
</html>

【运行结果】:

图片[12]|Django开发-模板系统|leon的博客

1.3.1.2 for … empty

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% empty %}
    <li>暂时还没有数据哦!</li>
{% endfor %}
</ul>

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% empty %}
    <li>暂时还没有数据哦!</li>
{% endfor %}
</ul>
</html>

【运行结果】:

图片[13]|Django开发-模板系统|leon的博客

1.3.2 if判断

1.3.2.1 if,elif和else

{% if user_list %}
  用户人数:{{ user_list|length }}
{% elif black_list %}
  黑名单数:{{ black_list|length }}
{% else %}
  没有用户
{% endif %}

1.3.2.2 if和else

{% if user_list|length > 5 %}
  七座豪华SUV
{% else %}
    黄包车
{% endif %}

提示|:if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。

【示例】:views.py

def template_test(request):
name_list = ['张三', '李四', '王五']
name_list2 = [['张三0', '李四0', '王五0'], ['张三1', '李四1', '王五1']]
    name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
    return render(
        request,
        'template_test.html',
        {
            'name_list': name_list,
            'name_dict': name_dict
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>===============if...elif...else测试==================</p>
{% if p3 %}
    <p>p3:{{ p3 }}</p>
{% elif p2 %}
    <p>p2:{{ p2 }}</p>
{% else %}
    <p>什么人都没有!</p>
{% endif %}

<p>===============if...else测试=====================</p>
{% if name_list|length >= 3 %}
    <p>需要打两辆车</p>
{% else %}
    <p>需要打一辆车</p>
{% endif %}
</body>
</html>

【运行结果】:

图片[14]|Django开发-模板系统|leon的博客

1.3.3 with别名

定义一个中间变量,多用于给一个复杂的变量起别名。注意等号左右不要加空格。

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

{% with business.employees.count as total %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

【示例】:views.py

def template_test(request):
name_list = ['张三', '李四', '王五']
name_list2 = [['张三0', '李四0', '王五0'], ['张三1', '李四1', '王五1']]
    name_dict = {'name1': '张三', 'name2': '李四', 'name3': '王五'}
    return render(
        request,
        'template_test.html',
        {
            'name_list': name_list,
            'name_dict': name_dict
        }
    )

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>with语句测试</p>
{{ name_list2.1.1 }}

<hr>

{% with name=name_list2.1.1 %}
    {{ name }}
{% endwith %}
</body>
</html>

【运行结果】:

图片[15]|Django开发-模板系统|leon的博客

1.3.4 csrf_token安全防护

这个标签用于跨站请求伪造保护。在页面的form表单里面写上{% csrf_token %}

1.3.5 注释

{# ... #}

1.3.6 注意事项

  1. Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}
...
{% endif %}
  1. Django的模板语言中属性的优先级大于方法:
def xx(request):
    d = {"a": 1, "b": 2, "c": 3, "items": "100"}
    return render(request, "xx.html", {"data": d})

如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:{{ data.items }}默认会取d的items key的值。

1.4 母板

1.4.1 为什么要有模板和继承

html页面有重复的代码,把它们提取出来放到一个单独的html文件,其他的页面只需要继承母版就可以了,可以减少代码冗余。

1.4.2 使用的步骤

  1. 把公用的HTML部分提取出来,放到html文件中;
  2. 在html中,通过定义block,把每个页面不同的部分区分出来;
  3. 在具体的页面中,先继承母版;
  4. 然后block名去指定替换母版中相应的位置;

1.4.3 使用母版和继承的注意事项

  1. {% extends ‘base.html’ %}中母版文件html要加引号
  2. {% extends ‘base.html’ %}必须放在子页面的第一行
  3. 可以在html中定义很多block,通常我们会额外定义page-css和page-js两个块
  4. py相应的函数中返回的是对应的子页面文件而不是 base.html
  5. 提示:我们通常会在母板中定义页面专用的CSS块和JS块,方便子页面替换。

1.4.4 模板格式示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>母版模板</title>
  {% block page-css %}
  {# CSS块 #}
  {% endblock %}
</head>
<body>

<h1>这是母板的标题</h1>
{% block page-main %}
{# 主要内容块 #}
{% endblock %}

<h1>母板底部内容</h1>
{% block page-js %}
{# JS块 #}
{% endblock %}
</body>
</html>

1.4.5 继承母板

在子页面中在页面最上方使用下面的语法来继承母板:

{% extends 'base.html' %}

1.4.6 块(block)

通过在母板中使用{% block xxx %}来定义”块”;

在子页面中通过定义母板中的block名来对应替换母板中相应的内容:

{% block page-main %}
  <p>世情薄</p>
  <p>人情恶</p>
  <p>雨送黄昏花易落</p>
{% endblock %}

1.4.7 组件

可以将重复的代码包装成一个独立的小html文件,这个小html文件叫做组件。可以将常用的页面内容如导航条、页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入:

{% include 'navbar.html' %}

1.4.8 模板使用示例

【示例】:母版页面:base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->

    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="https://v3.bootcss.com/favicon.ico">

    <title>BMS-图书管理系统</title>
    <!-- Bootstrap core CSS -->
    {% load static %}
    <link href="{% static 'bootstrap/css/bootstrap.min.css'%}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="{% static 'dashboard.css'%}" rel="stylesheet">
    <link rel="stylesheet" href="{% static 'fontawesome/css/font-awesome.min.css'%}">

    {% block page-css %}
    {% endblock %}
</head>

<body>
{% include 'navbar.html' %}

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
            <ul class="nav nav-sidebar">
                <li class="{% block publisher_class %}{% endblock %}"><a href="/publisher_list/">出版社列表页</a></li>
                <li class="{% block book_class %}{% endblock %}"><a href="/book_list/">书籍列表</a></li>
                <li class="{% block author_class %}{% endblock %}"><a href="/author_list/">作者列表</a></li>
            </ul>

        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            {# 这里是每个页面不同的部分 #}
            {% block page-main %}
            {% endblock %}
        </div>
    </div>
</div>

<div class="modal fade" tabindex="-1" role="dialog" id="myModal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">用户信息</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="inputEmail3" class="col-sm-2 control-label">邮箱</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" id="inputEmail3" placeholder="Email">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="inputPassword3" class="col-sm-2 control-label">密码</label>
                        <div class="col-sm-10">
                            <input type="password" class="form-control" id="inputPassword3" placeholder="Password">
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary">保存</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="{% static 'jquery-3.3.1.js'%}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js'%}"></script>

{% block page-js %}

{% endblock %}

</body>
</html>

【示例】:导航栏组件:navbar.html

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="https://v3.bootcss.com/examples/dashboard/#">BMS-S10</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
                <li><a href="https://v3.bootcss.com/examples/dashboard/#">Dashboard</a></li>
                <li><a href="https://v3.bootcss.com/examples/dashboard/#">Settings</a></li>
                <li><a href="https://v3.bootcss.com/examples/dashboard/#">Profile</a></li>
                <li><a href="https://v3.bootcss.com/examples/dashboard/#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
                <input type="text" class="form-control" placeholder="Search...">
            </form>
        </div>
    </div>
</nav>

【示例】:出版社列表页面:publisher_list.html

{% extends 'base.html' %}

{% block page-main %}

    <h1 class="page-header">出版社管理页面</h1>

    <div class="panel panel-primary">
        <!-- Default panel contents -->
        <div class="panel-heading">出版社列表 <i class="fa fa-thumb-tack pull-right"></i></div>
        <div class="panel-body">
            <div class="row" style="margin-bottom: 15px">
                <div class="col-md-4">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="Search for...">
                        <span class="input-group-btn">
                                    <button class="btn btn-default" type="button">搜索</button>
                                </span>
                    </div><!-- /input-group -->
                </div><!-- /.col-md-4 -->
                <div class="col-md-1 pull-right">
                    <button class="btn btn-success" data-toggle="modal" data-target="#myModal">新增</button>
                </div>

            </div><!-- /.row -->

            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>#</th>
                    <th>id</th>
                    <th>出版社名称</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for publisher in publisher_list %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ publisher.id }}</td>
                        <td>{{ publisher.name }}</td>
                        <td>
                            <a class="btn btn-danger" href="/delete_publisher/ id={{ publisher.id }}">删除</a>
                            <a class="btn btn-info" href="/edit_publisher/ id={{ publisher.id }}">编辑</a>
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>

            <nav aria-label="Page navigation" class="text-right">
                <ul class="pagination">
                    <li>
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                    <li><a href="#">1</a></li>
                    <li><a href="#">2</a></li>
                    <li><a href="#">3</a></li>
                    <li><a href="#">4</a></li>
                    <li><a href="#">5</a></li>
                    <li>
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>

{% endblock %}

{% block publisher_class %}
    active
{% endblock %}

【示例】:书籍列表页面:book_list.html

{# 继承母版 #}
{% extends 'base.html' %}

{# 把自己页面的内容 塞到母版里面相应的位置 #}
{% block page-main %}
   <h1 class="page-header">书籍管理页面</h1>
            <div class="panel panel-primary">
                <!-- Default panel contents -->
                <div class="panel-heading">书籍列表 <i class="fa fa-thumb-tack pull-right"></i></div>
                <div class="panel-body">
                    <div class="row" style="margin-bottom: 15px">
                        <div class="col-md-4">
                            <div class="input-group">
                                <input type="text" class="form-control" placeholder="Search for...">
                                <span class="input-group-btn">
                                    <button class="btn btn-default" type="button">搜索</button>
                                </span>
                            </div><!-- /input-group -->
                        </div><!-- /.col-md-4 -->
                        <div class="col-md-3 pull-right">
                            <a href="/add_book/" class="btn btn-success pull-right">新页面添加</a>
                            <button class="btn btn-success pull-right" data-toggle="modal" data-target="#myModal">新增</button>
                        </div>

                    </div><!-- /.row -->

                    <table class="table table-bordered">
                        <thead>
                        <tr>
                            <th>#</th>
                            <th>id</th>
                            <th>书名</th>
                            <th>出版社名称</th>
                            <th>操作</th>
                        </tr>
                        </thead>
                        <tbody>
                        {% for i in all_book %}
                            <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>{{ i.id }}</td>
                                <td>{{ i.title }}</td>
                                <td>{{ i.publisher.name }}</td>
                                <td>
                                    <a class="btn btn-danger" href="/delete_book/ id={{ i.id }}">删除</a>
                                    <a class="btn btn-info" href="/edit_book/ id={{ i.id }}">编辑</a>
                                </td>
                            </tr>
                        {% empty %}
                            <tr>
                                <td colspan="5" class="text-center">暂时没有数据哦~</td>
                            </tr>
                        {% endfor %}
                        </tbody>
                    </table>

                    <nav aria-label="Page navigation" class="text-right">
                        <ul class="pagination">
                            <li>
                                <a href="#" aria-label="Previous">
                                    <span aria-hidden="true">&laquo;</span>
                                </a>
                            </li>
                            <li><a href="#">1</a></li>
                            <li><a href="#">2</a></li>
                            <li><a href="#">3</a></li>
                            <li><a href="#">4</a></li>
                            <li><a href="#">5</a></li>
                            <li>
                                <a href="#" aria-label="Next">
                                    <span aria-hidden="true">&raquo;</span>
                                </a>
                            </li>
                        </ul>
                    </nav>
                </div>
            </div>
{% endblock %}

{% block book_class %}
    active
{% endblock %}

{% block page-css %}
    {% load static %}
{#    <link rel="stylesheet" href="{% static 'book_list_only.css' %}">#}
    <link rel="stylesheet" href="{% get_static_prefix %}book_list_only.css">
{% endblock %}

【示例】:作者列表页面:author_list.html

{% extends 'base.html' %}

{% block page-main %}
    <h1 class="page-header">作者管理页面</h1>

    <!-- 面板开始 -->
    <div class="panel panel-primary">
        <!-- Default panel contents -->
        <div class="panel-heading">作者列表 <i class="fa fa-thumb-tack pull-right"></i></div>
        <div class="panel-body">
            <div class="row" style="margin-bottom: 15px">
                <div class="col-md-4">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="Search for...">
                        <span class="input-group-btn">
                                    <button class="btn btn-default" type="button">搜索</button>
                                </span>
                    </div><!-- /input-group -->
                </div><!-- /.col-md-4 -->
                <div class="col-md-3 pull-right">
                    <a href="/add_author/" class="btn btn-success pull-right"><i class="fa fa-plus fa-fw"></i>新页面添加</a>
                    <button class="btn btn-success pull-right" data-toggle="modal" data-target="#myModal">新增
                    </button>
                </div>
            </div><!-- /.row -->

            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>#</th>
                    <th>id</th>
                    <th>作者名字</th>
                    <th>作品</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for author in author_list %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ author.id }}</td>
                        <td>{{ author.name }}</td>
                        <td>
                            {% for book in author.book.all %}
                                {{ book.title }}&nbsp;
                            {% endfor %}
                        </td>
                        <td>
                            <a class="btn btn-danger" href="/delete_author/ id={{ author.id }}"><i
                                    class="fa fa-trash-o fa-fw"></i>删除</a>
                            <a class="btn btn-info" href="/edit_author/ id={{ author.id }}"><i
                                    class="fa fa-pencil fa-fw"></i>编辑</a>
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>

            <nav aria-label="Page navigation" class="text-right">
                <ul class="pagination">
                    <li>
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                    <li><a href="#">1</a></li>
                    <li><a href="#">2</a></li>
                    <li><a href="#">3</a></li>
                    <li><a href="#">4</a></li>
                    <li><a href="#">5</a></li>
                    <li>
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>
{% endblock %}

{% block author_class %}
    active
{% endblock %}

{% block page-js %}
    <script src="/static/author_list_only.js"></script>
{% endblock %}

1.5 静态文件相关

1.5.1 {% static %}

利用Django模板语言内置的static方法拼接静态文件的路径:

{% load static %}
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">

引用JS文件时使用:

{% load static %}
<script src="{% static "mytest.js" %}"></script>

某个文件多处被用到可以存为一个变量:

{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>

1.5.2 {% get_static_prefix %}

利用内置的get_static_prefix获取静态文件路径的别名自行拼接路径:

{% load static %}
<link href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css" rel=stylesheet>

或者

{% load static %}
# 一个路径如果多次用到可以使用as保存到一个变量,后面直接使用变量代替具体路径
{% get_static_prefix as STATIC_PREFIX %}

<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />

1.6 自定义tag

1.6.1 simple_tag

和自定义filter类似,只不过接收更灵活的参数(参数个数大于2个)。

  • 定义注册simple tag
@register.simple_tag(name="plus")
def plus(a, b, c):
    return "{} + {} + {}".format(a, b, c)
  • 使用自定义simple tag
{% load mytag %}

{# simple tag #}
{% plus "1" "2" "abc" %}

1.6.2 inclusion_tag

多用于返回html代码片段。

【示例】:mytag.py

from django import template
# 生成注册示例,名字必须是register
register = template.Library()

@register.simple_tag(name="plus")
def plus(a, b, c):
    return "{} + {} + {}".format(a, b, c)

@register.inclusion_tag('result.html')
def show_results(n):
    n = 1 if n < 1 else int(n)
    data = ["第{}项".format(i) for i in range(1, n+1)]
    return {"data": data}

【示例】:urls.py

urlpatterns = [
    url(r'^template_test/', views.template_test)
]

【示例】:result.html

<ul>
  {% for choice in data %}
    <li>{{ choice }}</li>
  {% endfor %}
</ul>

【示例】:template_test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template_test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{% load mytag %}
{% show_results 10 %}
{% plus "1" "2" "abc" %}
</html>

【运行结果】:

图片[16]|Django开发-模板系统|leon的博客

第2章 参考资料

http://www.cnblogs.com/liwenzhou/p/7931828.html

https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#std:templatetag-for

温馨提示:本文最后更新于2022-12-20 20:57:44,已超过493天没有更新。某些文章具有时效性,若文章内容或图片资源有错误或已失效,请联系站长。谢谢!
转载请注明本文链接:https://blog.leonshadow.cn/763482/1602.html
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享