Django04-模板系统Template

一、模板支持的语法

Django模板中只需要记两种特殊符号:

{{ }}表示变量,在模板渲染的时候替换成值
{% %}表示逻辑相关的操作。

二、 变量(使用双大括号来引用变量)

1、语法格式:{{var_name}}

变量名由字母数字和下划线组成。

例子

urls.py文件指定url和views中的函数对应关系
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^time/$', views.localtime),
]

views.py文件中编写函数,指定页面并传递字典参数
from django.shortcuts import render, HttpResponse
import datetime

def localtime(request):
    time = datetime.datetime.now()
    return render(request, 'time.html', {'time':time})

time.html编写html页面,通过双大括号接收字典参数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ time }}
</body>
</html>

访问http://127.0.0.1:8000/time/显示时间
Feb. 15, 2019, 1:53 p.m.

2、 深度变量的查找(万能的句点号)

上面例子中,我们传递的参数值主要是字符串,然而模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在Django模板中遍历复杂数据结构的关键是句点字符 (.)。

urls.py和views.py中的代码不变,time.html文件修改如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>日期:{{ time.year }}年{{ time.month }}月{{ time.day }}日</p>
</body>
</html>

访问网页显示如下:
日期:2019年2月15日

例子2:循环显示列表中的内容

views.py
def people(request):
    people = [
        {'name':'tom', 'age':20},
        {'name':'mike', 'age':21},
        {'name':'jack', 'age':22},
    ]
    return render(request, 'people.html', {'people':people})

people.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table{
            border: 1px solid black;
            border-spacing: 0;
            width: 300px;
        }
        table td{
            border:1px solid;
            text-align: center;
            padding: 10px 0px;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <td>ID</td>
        <td>姓名</td>
        <td>年龄</td>
    </tr>
    {% for people in people %}
        <tr>
        <td>{{ forloop.counter }}</td>
        <td>{{ people.name }}</td>
        <td>{{ people.age }}</td>
        </tr>
    {% endfor %}
</table>
</body>
</html>

访问页面结果显示:

例子3:

def template_test(request):
    l = [11, 22, 33]
    d = {"name": "alex"}

    class Person(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def dream(self):
            return "{} is dream...".format(self.name)

    Alex = Person(name="Alex", age=34)
    Egon = Person(name="Egon", age=9000)
    Eva_J = Person(name="Eva_J", age=18)

    person_list = [Alex, Egon, Eva_J]
    return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})

模板中支持的写法:

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

注:当模板系统遇到一个(.)时,会按照如下的顺序去查询:

  • 在字典中查询
  • 属性或者方法
  • 数字索引

3 变量的过滤器(filter)的使用

语法格式:{{obj|filter:param}}
'|'左右没有空格

value1 = 'abc'
value2 = 11
value3 = []
value4 = None
value5 = 'name is tom and age is 20'
value6 = '姓名小明年龄20'
value7 = '<a herf="#">跳转</a>'
value8 = 'https://www.baidu.com/?a=1&b=2'

<p>日期:{{ time.year}}年{{ time.month}}月{{ time.day}}日</p>
#日期:2019年2月15日

格式化日期
<p>日期:{{ time|date:"Y年m月d日" }}</p>
#日期:2019年02月15日

<p>日期:{{ time|date:"Y-m" }}</p>
#日期:2019-02

字母大写
<p>{{ value1|upper }}</p>
#ABC

变量值加2,如果变量是float则只显示整数部分
<p>{{ value2|add:2 }}</p>
#13

首字母大写
<p>{{ value1|capfirst }}</p>
#Abc

title标题
{{ value|title }}

ljust左对齐
{{ value|ljust:"10" }}

rjust右对齐
{{ value|rjust:"10" }}

center居中
{{ value|center:"15" }}

join使用字符串拼接列表。同python的str.join(list)。
{{ value |join:" // " }}

切除掉指定字符串,可以用于切掉空格
<p>{{ value1 | cut:'b' }}</p>
#ac

如果值为false,则显示默认值
<p>{{ value3 | default:'值是假或空' }}</p>
#值是假或空

如果值为None,则显示默认值
<p>{{ value4 | default_if_none:'值是None' }}</p>
#值是None

只显示前3个单词,以空格为分隔,后面的内容显示为...
<p>{{ value5 | truncatewords:3 }}</p>
#name is tom ...

只显示前10个字符,后面的内容显示为...,而且这10个字符包括3个点,也就是只显示前7个字符
<p>{{ vlaue6 | truncatechars:7 }}</p>

<p>{{ value7 }}</p>
#<a herf="#">跳转</a>

<p>去掉自动转义:
  {% autoescape off %}
    {{ value7 }}
{% endautoescape %}
</p>
#跳转

<p>{{ value7 | safe }}</p>
#跳转

<p>{{ value7 | striptags }}</p>
#跳转

转成KB格式
<p>{{ value2 | filesizeformat }}</p>
#11 bytes

<p>第1个字符:{{ value1 | first }}</p>
#a

<p>最后1个字符:{{ value1 | last }}</p>
#c

<p>显示长度:{{ value1 | length }}</p>
#3

<p>切片:{{ value1 | slice:'1::' }}</p>
#bc

<p>{{ value8 | urlencode }}</p>
#https%3A//www.baidu.com/%3Fa%3D1%26b%3D2

三、 标签(tag)的使用(使用大括号和百分号的组合来表示tag)

语法格式: {% tags %}

1、 if elif和else的使用

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

{% if %}标签判断一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容。

{% if num >= 100 %}
    {% if num > 200 %}
        <p>num大于200</p>
    {% else %}
        <p>num大于100小于200</p>
    {% endif %}

{% elif num < 100%}
    <p>num小于100</p>

{% else %}
    <p>num等于100</p>

{% endif %}

{% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
{% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:{% if obj1 and obj2 or obj3 %}

2、 for的使用

{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容。

<ul>
{% for obj in list %}
    <li>{{ obj.name }}</li>
{% endfor %}
</ul>

在标签里添加reversed来反序循环列表:

{% for obj in list reversed %}
...
{% endfor %}

{% for %}标签可以嵌套:

{% for country in countries %}
    <h1>{{ country.name }}</h1>
    <ul>
     {% for city in country.city_list %}
        <li>{{ city }}</li>
     {% endfor %}
    </ul>
{% endfor %}

系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息

1、forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:

{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}

2、forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0

3、forloop.revcounter 倒序排序,最小为1

4、forloop.revcounter0 倒序排序,最小为0

5、forloop.first当第一次循环时值为True,在特别情况下很有用:

{% for object in objects %} 
{% if forloop.first %}<li class="first">{% else %}<li>{% endif %} 
{{ object }} 
</li> 
{% endfor %} 

6、forloop.last 当前循环是不是最后一次循环(布尔值)

7、forloop.parentloop 本层循环的外层循环

# 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
# 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
# 在其他非循环的地方,你的forloop变量仍然可用

3、 empty的使用

{% empty %}不需要写{% endempty %}

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% empty %}
    <li>空空如也</li>
{% endfor %}
</ul>

4、 with

定义一个中间变量,用更简单的变量名替代复杂的变量名

{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}

5、 csrf_token标签

用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。

6、 url

引用路由配置的地址别名

<form action="{% url "bieming"%}" >
          {%csrf_token%}
          <input type="text">
          <input type="submit"value="提交">
</form>

7、 verbatim

禁止render

{% verbatim %}
{{ hello }}
{% endverbatim %}

8、 注释

{# ... #}

9、 注意事项

1). Django的模板语言不支持连续判断,即不支持以下写法:

{% if a > b > c %}
...
{% endif %}

2). 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的值100。

四、extend模板继承

到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用Django模板系统来创建整个HTML页面。 这就带来一个常见的Web开发问题:在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django解决此类问题的首选方法是使用一种优雅的策略—— 模板继承 。

本质上,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。

1、定义基础模板

该模板将由子模板所继承,以下是基础模板base.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>欢迎访问</h1>
{% block content %}{% endblock %}

{% block footer %}
<hr>
<p>Thanks for visit my site</p>
{% endblock %}
</body>
</html>

使用模板标签: {% block %} 。 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。

2、继承母板

现在我们已经有了一个基本模板,我们可以通过多个子模板模板来继承它,子页面中在页面最上方使用{% extends 'base.html' %}语法来继承母板

user.html
{% extends "base.html" %}
{% block title %}user{% endblock %}
{% block content %}
<p>用户管理界面</p>
{% endblock %}

host.html
{% extends "base.html" %}
{% block title %}host{% endblock %}
{% block content %}
<p>主机管理界面</p>
{% endblock %}

如果想进行站点级的设计修改,仅需修改 base.html ,所有其它模板会立即反映出所作修改。

3、块(block)

通过在母板中使用{% block xxx %}来定义"块"。
在子页面中通过定义母板中的block名来对应替换母板中相应的内容。

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

4、组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。

{% include 'navbar.html' %}

以下是其工作方式:

1、在加载user.html和host.html模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。
2、模板引擎立即装载其父模板,即base.html。此时,base.html中的三个{% block %}标签中的内容将使用子模板的内容替换这些block。
3、由于子模板并没有定义footer块,模板系统将使用在父模板中定义的值。

使用继承的一种常见方式是下面的三层法:

<1> 创建base.html模板,在其中定义站点的主要外观,这些都是不常修改甚至从不修改的部分。
<2> 为网站的每个区域创建base_SECTION.html模板(例如, base_photos.html 和 base_form.html )。这些模板对base.html进行拓展,并包含区域特定的风格与设计。
<3> 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。

以下是使用模板继承的一些诀窍:

<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
<2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越多越好。
<3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
<4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block标签的工作方式是双向的。
也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。

五、静态文件相关

settings.py文件:

STATIC_URL = '/static/'
STATICSFILES_DIR = [
    os.path.join(BASE_DIR, 'statics'),
]

将images文件夹、mytest.js等静态文件放到创建的statics文件夹中

模板文件:

{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />

引用JS文件时使用:
{% load static %}
<script src="{% static "mytest.js" %}"></script>

某个文件多处被用到可以存为一个变量
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>

猜你喜欢

转载自www.cnblogs.com/dxnui119/p/10434556.html