61-Django进阶(模板系统)

1、模板系统

  模板的实质就是用来替换对应的HTML元素,让网页“动”起来。

1.1 常用语法

  与变量相关的用{{ }},与逻辑相关的用{% %}。注释用{#  ...  #}

  模板中支持的写法:

1 {# 取list中的第一个参数 #}
2 {{ list.0 }}
3 {# 取字典中key的值 #}
4 {{ dict.name }}
5 {# 取对象的name属性 #}
6 {{ person_list.0.name }}
7 {# .操作只能调用不带参数的方法 #}
8 {{ person_list.0.dream }}

  示例模板代码: 

 1     <hr>
 2     {{ namehtml }}
 3 
 4     <hr>
 5     {{ agehtml }}
 6 
 7     <hr>
 8 
 9 <h3>模版之列表操作</h3>
10     {{ namelisthtml }}
11     <br />
12     {{ namelisthtml.0 }}  {# 取第一个元素 #}
13     {{ namelisthtml.1 }}  {# 取第二个元素 #}
14     {{ namelisthtml.2 }}  {# 取第三个元素 #}
15     {{ namelisthtml.3 }}  {# 取第四个元素 #}
16     {{ namelisthtml.4 }}  {# 取第五个元素 如果没有第五个元素,则代表取不到,不会在页面上显示#}
17 
18  <h3>模版之字典操作</h3>
19     {{ namedicthtml }}
20     <br />
21     {{ namedicthtml.first_name }}  {# 取出key对应的value #}
22     {{ namedicthtml.last_name }}  {# 取出key对应的value #}
23 
24     <hr>
25     {{ p1html }}  {# 得到的是对象p1的内存地址 #}
26     <br />
27     {{ p2html }}  {# 得到的是对象p2的内存地址 #}
28     <br />
29     {{ p1html.name }}  {# 得到对象p1的name属性 #}
30     {{ p1html.age }}  {# 得到对象p1的age属性 #}
31     <br />
32     {{ p2html.name }}  {# 得到对象p2的name属性 #}
33     {{ p2html.age }}  {# 得到对象p2的age属性 #}
34     <br />
35     {{ p1html.speak }}  {# 调用对象p1的方法(只能调用无参数的方法) #}
36 
37     <hr>
38     {{ objlisthtml }}  {# 获取所有对象 #}
39     <br />
40     {{ objlisthtml.0 }}  {# 获取第一个对象#}
41     <br />
42     {{ objlisthtml.1 }}  {# 获取第二个对象 #}
43     <br />
44     {{ objlisthtml.0.name }}  {# 获取对象的name属性,注意:.操作只能调用不带参数的方法  #}
45     {{ objlisthtml.0.age }}  {# 获取对象的age属性 #}
46     <br />
47     {{ objlisthtml.1.name }}  {# 获取对象的name属性 #}
48     {{ objlisthtml.1.age }}  {# 获取对象的age属性 #}
49     <br />
50     {{ objlisthtml.0.speak }}  {# 调用第一个对象的speak方法 #}
51     {{ objlisthtml.1.speak }}  {# 调用第二个对象的speak方法 #}

  与模板对应的后台代码:

 1 def template_test(request):
 2     name = "druid"
 3     age = 18
 4     p1 = Person("druid", 18)
 5     p2 = Person("john", 19)
 6 
 7     obj_list = [p1, p2]
 8 
 9 return render(request, "tmp_test.html",
10                   {
11                       "namehtml": name,
12                       "agehtml": age,
13                       "namelisthtml": name_list,
14                       "namedicthtml": name_dict,
15                       "p1html": p1,
16                       "p2html": p2,
17                       "objlisthtml": obj_list,
18                     })

 

1.2 filter

  语法: {{ value|filter_name:参数 }} ("|"左右没有空格!

  示例模板代码:

 1     {{ unknownhtml }}  {# 如果没有给变量传递元素,则不会在页面上显示 #}
 2     {{ unknownhtml|default:"没有给变量'unknownhtml'传值,使用自定义默认值" }}
 3 
 4     <hr>
 5     <p>
 6         长度:
 7         {{ namehtml|length }}  {# 对象为字符串,则是字符串长度 #}
 8         {{ namelisthtml|length }}  {# 对象为列表,则是列表元素个数 #}
 9         {{ namedicthtml|length }}  {# 对象为字典,则是字典元素个数 #}
10     </p>
11 
12     <hr>
13     <p>文件大小:
14         {{ filesizehtml1|filesizeformat }}  {# 默认情况下,传递的值单位会被认为是bytes #}
15         {{ filesizehtml2|filesizeformat }}  {# 默认情况下,传递的值单位会被认为是bytes #}
16         {{ filesizehtml3|filesizeformat }}  {# 默认情况下,传递的值单位会被认为是bytes #}
17         {{ filesizehtml4|filesizeformat }}  {# 默认情况下,传递的值单位会被认为是bytes #}
18     </p>
19 
20     <hr>
21     <p>列表切片:
22         {{ namelisthtml|slice:"0:" }}  {# 和列表切片一样,左取右不取 #}
23         {{ namelisthtml|slice:":-1" }}  {# 取除了最后一位元素外的所有元素 #}
24         {{ namelisthtml|slice:"1:-1" }}  {# 取第二位到除了最后一位的所有元素 #}
25     </p>
26     <p>字符串切片:
27         {{ namehtml|slice:"0:2" }}
28         {{ namedicthtml.first_name|slice:":-1" }}  {# 和列表切片一样,左取右不取 #}
29     </p>
30 
31     <hr>
32     <p>
33         未格式化之前的时间:{{ nowhtml }}
34         格式化之后的时间:{{ nowhtml|date:"Y-m-d H:i:s" }}
35     </p>
36 
37     <hr>
38         默认情况下后端传递标签浏览器不会作为标签处理:{{ a_html }}
39         <br>
40         使用safe方法后浏览器会对标签进行处理:{{ a_html_safe|safe }}
41         <br>
42         攻击:{{ attackhtml }}  {# 加了safe之后就会一直弹窗 #}
43 
44     <hr>
45     <h5>{{ parastrhtml }}</h5>
46     <h5>{{ parastrhtml|truncatechars:32 }}</h5>

  与模板对应的后台代码:

 1 def template_test(request):
 2     file_size1 = 1024
 3     file_size2 = 1048576
 4     file_size3 = 1073741824
 5     file_size4 = 1099511627776
 6 
 7 
 8     import datetime
 9     now_time = datetime.datetime.now()
10     print(now_time)
11 
12     a_tag = "<a href='http://www.baidu.com'>我是后端传过来的超链接,默认不会被浏览器作为a标签处理</a>"
13     a_tag_safe = "<a href='http://www.baidu.com'>我是后端传过来的超链接,使用safe方法后会被作为a标签处理</a>"
14     attack_script = "<script>for(1;;)alert('弹死你!');</script>"
15 
16     para_str = """
17     大段的文本:
18     《悲惨世界》是由法国作家维克多·雨果在1862年发表的一部长篇小说,其内容涵盖了拿破仑战争和之后的十几年的时间。
19     故事的主线围绕主人公土伦苦刑犯冉·阿让(Jean Valjean)的个人经历,融进了法国的历史、革命、战争、道德哲学、法律、正义、宗教信仰。
20     """
21 
22     return render(request, "tmp_test.html",
23                   {
24                       "namelisthtml": name_list,
25                       "filesizehtml1": file_size1,
26                       "filesizehtml2": file_size2,
27                       "filesizehtml3": file_size3,
28                       "filesizehtml4": file_size4,
29                       "nowhtml": now_time,
30                       "a_html": a_tag,
31                       "a_html_safe": a_tag_safe,
32                       "attackhtml": attack_script,
33                       "parastrhtml": para_str,
34                   })

 

1.3 自定义filter 

  在app文件夹下,创建templatetags包(名字固定),然后再新建myfilter.py文件作为自定义filter:

 1 """
 2 该模块为自定义filter,文件夹的名字只能是templatetags
 3 """
 4 from django import template
 5 
 6 
 7 register = template.Library()  # 生成注册用的实例,固定写法
 8 
 9 
10 @register.filter(name="sb")  # 告诉Django的模版语言我现在有一个自定义的filter方法,名字叫sb。name="sb"这里相当于给add_sb取了个sb的别名。
11 def add_sb(arg):
12     return "{} is sb".format(arg)
13 
14 
15 @register.filter(name="self_str")  # 告诉Django的模版语言我现在有一个自定义的filter方法,名字叫self_str。name="self_str"这里仍然相当于取别名。
16 def add_self_str(arg1, arg2):
17     """
18     :param arg1: 第一个参数是管道符左边的变量
19     :param arg2: 第二个参数是冒号后面的那个变量
20     :return:
21     """
22     return "{} {}".format(arg1, arg2)

  创建userdefinedfilter.html文件,使用自定义filter模板代码:      

 1     {% load myfilter %}   {# 加载自定义的filter模块 #}
 2     <h4>单参数的自定义filter</h4>
 3     {{ name_list_html.0|sb }}  {# 使用自定义filter的sb方法 #}
 4     <br/>
 5     {{ name_list_html.1|sb }}  {# 使用自定义filter的sb方法 #}
 6 
 7     <hr>
 8 
 9     <h4>多个参数的自定义filter</h4>
10     {{ name_list_html.0|self_str:"是好人吗?" }}  {# 使用自定义filter的self_str方法,name_list_html.0是第一个参数,"是好人吗?"是第二个参数#}
11     <br/>
12     {{ name_list_html.0|self_str:"是好人" }}  {# 使用自定义filter的self_str方法 #}

  与模板对应的后台代码:

1 def defined_filter(request):
2     name_list = ["natasha", "john", "jane"]
3 
4     return render(request, "userdefinedfilter.html", {"name_list_html": name_list})

 

1.4 tags

  与逻辑相关的被称为tags。

  1.4.1 for循环

    for循环可用的一些参数:

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

    for循环示例:

 1     <h3>模版之循环操作</h3>
 2         <ul>
 3             <ol>
 4             {% for name in namelisthtml %}
 5                 <li>{{ name }}</li>
 6             {% endfor %}
 7             </ol>
 8         </ul>
 9 
10         <ul>
11             {% for name in namelisthtml %}
12                 <li>{{ forloop.counter0 }} - {{ name }}</li>  {# 循环迭代的次数,循环编号从0开始 #}
13             {% endfor %}
14         </ul>
15 
16         <ul>
17             {% for name in namelisthtml %}
18                 <li>{{ forloop.counter }} - {{ name }}</li>  {# 循环迭代的次数,循环编号从0开始 #}
19             {% endfor %}
20         </ul>
21 
22         <ul>
23             {% for name in namelisthtml %}
24                 <li>{{ forloop.revcounter }} - {{ name }}</li>  {# 循环迭代的次数,反着排列 #}
25             {% endfor %}
26         </ul>
27 
28         <ul>
29             {% for name in namelisthtml %}
30                 {% if forloop.first %}
31                     <li class="c1">{{ forloop.counter}} - {{ name }}</li>
32                 {% elif forloop.last %}
33                     <li class="c2">{{ forloop.counter}} - {{ name }}</li>
34                 {% else %}
35                     <li>{{ forloop.counter}} - {{ name }}</li>
36                 {% endif %}
37             {% endfor %}
38         </ul>
39 
40         <ul>
41             {% for name in namelisthtml %}
42                 {% if forloop.first %}
43                     <li class="c1">{{ forloop.counter}} - {{ name }}</li>
44                 {% else %}
45                     <li class="{% if forloop.last %}c2{% endif %}">{{ forloop.counter}} - {{ name }}</li>  {# for循环在class里也可以 #}
46                 {% endif %}
47             {% endfor %}
48         </ul>
49 
50     <hr>
51     <h3>模版之双层循环操作</h3>
52         <ul>
53             <ol type="A">
54                 {% for name_list in namelistshtml %}
55                     <li>{{ forloop.counter }}</li>
56                         {{ name_list }}
57                     <ul>
58                         <ol type="a">
59                             {% for name in name_list %}
60                                 <div> {{ forloop.parentloop.counter }} </div> {# 外层for循环 #}
61                                 <li>{{ forloop.counter }}</li>
62                                 {{ name }}
63                             {% endfor %}
64                         </ol>
65                     </ul>
66                 {% endfor %}
67             </ol>
68         </ul>

 

  1.4.2 for empty

1     <h3>模版之for empty</h3>
2     {% for name in namelisthtml1 %}
3         {{ name }}  {# 有数据就显示 #}
4     {% empty %}
5         {{ "没有数据" }}  {# 没有数据就显示这里 #}
6     {% endfor %}

 

  1.4.3 if elif else 

   if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。但不是支持连续判断!(类似a > b > c这种)。

1 {% if user_list %}
2   用户人数:{{ user_list|length }}
3 {% elif black_list %}
4   黑名单数:{{ black_list|length }}
5 {% else %}
6   没有用户
7 {% endif %}

  注意,执行语句中的空格会严格出现在生成的HTML语句中!如下两段代码在生成的HTML语句中不一样:第二段代码的执行语句多了空格,因此生成的HTML语句会多出空格,如果要查找这些元素,而没有注意空格的问题,那么就会查找不到。

<a href="{% if menu.url_choice == 0 %}{% url menu.url_name %}{% else %} {{menu.url_name}} {% endif %}">
  {{ menu.name }}
</a>
<a href="{% if menu.url_choice == 0 %}  {% url menu.url_name %}   {% else %}  {{menu.url_name}}  {% endif %}">
    {{ menu.name }}
</a>

 

  1.4.4 if else

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

 

  1.4.5 with用法

    with用来给变量取别名,一般用于变量名字过长时。

1     <h3>with用法</h3>
2     {% with name=namelistshtml.1.1 %}  {# 变量名字太长时可以用with来取别名 #}
3         {{ name }}
4     {% endwith %}

 

1.5 自定义simple_tag

  simple_tag和filter类似,区别在于simple_tag支持多参数(大于2)。

  自定义simple_tag:在app文件夹下,创建templatetags包(名字固定),然后再新建mysimpletag.py文件作为自定义simple_tag。

 1 """
 2 simple_tag和filter类似,区别在于simple_tag支持多参数(大于2)
 3 """
 4 from django import template
 5 
 6 
 7 register = template.Library()  # 生成注册用的实例,固定写法
 8 
 9 
10 @register.simple_tag(name="mysimpletag")  # 告诉Django的模版语言我现在有一个自定义的simple_tag方法,名字叫my_smp_tag。name参数这里仍然相当于取别名。
11 def my_smp_tag(arg1, arg2, arg3, arg4):
12     return "{} {} {} {}".format(arg1, arg2, arg3, arg4)

  创建mysimpletag.html文件,使用自定义的simpletag:

1     {% load mysimpletag %}  {# 加载自定义的simple_tag #}
2     {% mysimpletag "my" "name" "is" "druid" %}

  与模版对应的后台代码示例:

1 def my_simple_tag(request):
2 
3     return render(request, "mysimpletag.html")

 

1.6 inclusion_tag

  inclusion_tag多用于返回html代码片段。

  自定义inclusion_tag:在app文件夹下,创建templatetags包(名字固定),然后再新建inclusiontag.py文件作为自定义inclusion_tag。

 1 """
 2 inclusion_tag用来返回html代码
 3 """
 4 from django import template
 5 
 6 
 7 register = template.Library()  # 生成注册用的实例,固定写法
 8 
 9 
10 @register.inclusion_tag("results.html", name="myinclusiontag")
11 def my_inclusion_tag(n):
12     n = 1 if n < 1 else int(n)
13     data = ["第{}项".format(i) for i in range(1, n+1)]
14 
15     return {"results": data}
16 
17 
18 """
19 告诉Django的模版语言我现在有一个自定义的inclusion_tag方法,名字为myinclusiontag,
20 'results.html'文件是渲染HTML页面的内容
21 """

  创建results.html文件

1 <ul>
2     {% for line in results %}
3         <li>{{ line }}</li>
4     {% endfor %}
5 </ul>

  与模板对应的后台代码:

1 def my_inclusion_tag(request):
2 
3     return render(request, "inclusiontag.html")

  创建inclusiontag.html文件,使用inclusion_tag:

1 <body>
2     {% load inclusiontag %}
3     {% myinclusiontag 10 %}
4 
5     <hr>
6 
7     {% myinclusiontag 20 %}
8 </body>

 

1.7 注意事项

  Django的模板语言中属性的优先级大于方法。以下举例说明: 

1 def foo(request):
2     dict1 = {"a": 1, "b": 2, "c": 3, "items": "100"}
3 
4     return render(request, "bar.html", {"data": dict1})

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

{{ data.items }}

  默认会取dicts的items key的值,为100。而不是返回items()方法本身返回的(键,值)元组。

 

2、母版 

  通过在母板中使用{% block blockName %} {% endblock %}来定义"块",这个块可以被替换成不同的内容,一般用于页面会变化的地方。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="UTF-8">
 5   <meta http-equiv="x-ua-compatible" content="IE=edge">
 6   <meta name="viewport" content="width=device-width, initial-scale=1">
 7   <title>Title</title>
 8   {% block page-css %}  {# 该块用来进行css替换 #}
 9   
10   {% endblock %}
11 </head>
12 <body>
13 
14 <h1>下面部分是每个页面不同的部分,用来被替换</h1>
15 {% block page-content %}  {# page-content代表要替换的块名 #}
16 
17 {% endblock %}
18 <h1>母板底部</h1>
19 
20 {% block page-js %}  {# 该块用来进行js替换 #}
21 
22 {% endblock %}
23 </body>
24 </html>

 

2.1 继承母版

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

{% extends "base.html" %} 

  然后再定义块的内容,与母版相对应的块就会被子页面中定义的块的内容所代替。

1 {% block page-content %}
2     html语法
3     ......
4 {% endblock %}

 

3、组件

  可以将常用的页面内容如导航条,页尾信息等组件保存在单独的HTML文件中,

 1 <nav class="navbar navbar-inverse navbar-fixed-top">
 2     <div class="container-fluid">
 3         <div class="navbar-header">
 4             <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
 5                     aria-expanded="false" aria-controls="navbar">
 6                 <span class="sr-only">Toggle navigation</span>
 7                 <span class="icon-bar"></span>
 8                 <span class="icon-bar"></span>
 9                 <span class="icon-bar"></span>
10             </button>
11             <a class="navbar-brand" href="https://v3.bootcss.com/examples/dashboard/#">BMS</a>
12         </div>
13     </div>
14 </nav>

  然后在需要使用的地方按如下语法导入即可。

{% include 'navbar.html' %}

 

4、静态文件

  把路径写死的导入静态文件方法:

1     <link rel="stylesheet" type="text/css" href="/static/bootstrap/css/bootstrap.css"/>
2     <link rel="stylesheet" type="text/css" href="/static/dashboard.css"/>
3     <link rel="stylesheet" type="text/css" href="/static/fontawesome/css/font-awesome.css"/>
4 
5     <script type="text/javascript" src="/static/jquery-3.3.1.js"></script>
6     <script type="text/javascript" src="/static/bootstrap/js/bootstrap.js"></script>

 

  用{% load static %}的导入静态文件方法:

1     {% load static %}  {# 会去settings.py里面查找静态文件夹的别名 #}
2     <link rel="stylesheet" type="text/css" href="{% static 'bootstrap/css/bootstrap.css' %}"/>  {# 将别名和相对路径进行拼接 #}
3     <link rel="stylesheet" type="text/css" href="{% static 'dashboard.css' %}"/>
4     <link rel="stylesheet" type="text/css" href="{% static 'fontawesome/css/font-awesome.css' %}"/>
5 
6     <script type="text/javascript" src="{% static 'jquery-3.3.1.js' %}"></script>
7     <script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.js' %}"></script>

  还可以用get_static_prefix方法:

{% load static %}
<script type="text/javascript" src="{% get_static_prefix %} bootstrap/js/bootstrap.js"></script> 

  或者:

{% load static %}
{% get_static_prefix as STATIC_PREFIX %}

<script type="text/javascript" src="{{ STATIC_PREFIX }} bootstrap/js/bootstrap.js"></script>

 

  某个文件被多处引用时,还可以将其存为一个变量。

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

 

posted @ 2018-08-22 11:13  Druid_Py  阅读(175)  评论(0编辑  收藏  举报