05django模板层

目的

将页面的设计和Python的代码分离开会更干净简洁更容易维护

核心内容

  • 变量 {{var_name}}
  • 标签

变量 {{ var_name }}

1.变量的使用

首先新建一个html5的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ li }}</p>
</body>
</html>

在view中添加代码

from django.shortcuts import render

def test(request):
    # 传给模板的变量值可以是任意python类型,如下
    msg='hello world'
    dic={'k1':1,'k2':2}
    class Person(object):
        def __init__(self,name,age):
            self.name=name
            self.age=age

    obj=Person('egon',18)
    li = [1,'aaa',obj]

    return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li})
    # 注意:
    # 1、render函数的第三个参数包含了要传给模板的变量值,是一个字典类型,该字典中的key必须与模板文件中的变量名相对应,
    #  render函数会去templates目录下找到模板文件,然后根据字典中的key对应到模板文件中的变量名进行赋值操作,最后将赋值后的模板文件内容返回给浏览器
    # 2、可以将render函数的第三个参数简写为locals(),如下
    return render(request,'test.html',locals()) #locals()会将函数test内定义的名字与值转换为字典中的k与v

总结:

Django模板中. 有特殊的意义

list: 按list.index取值,注意不能用python原始取值方法list[0]

取list中的第一个参数
{{ list.0 }}

取字典中key的值
{{ d.name }}

取对象的name属性
{{ person_list.0.name }}

.操作只能调用不带参数的方法
{{ person_list.0.dream }}

调用字符串对象的upper方法,注意不要加括号
{{ msg.upper }}

取对象的name属性
{{ obj.name }}

取列表的第2个元素,然后变成大写
{{ li.1.upper }}

取列表的第3个元素,并取该元素的age属性
{{ li.2.age }}

过滤器

DJANGO模板自带了很多的过滤器,详细介绍:

https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/

语法

{{obj|filter__name:param}}

常用的过滤器

default

  
{{ value|default:"nothing"}}
如果value值没传的话就显示nothing

注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:

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

add

给变量加参数

{{ value|add:"2" }}
value是数字4,则输出结果为6。

{{ first|add:second }}
如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6] 。

lower upper

小写
{{ value|lower }}

大写
{{ value|upper}}

title

标题

{{ value|title }}

ljust

左对齐

"{{ value|ljust:"10" }}"

rjust

右对齐

"{{ value|rjust:"10" }}"

center

居中

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

length

{{ value|length }}

返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.

slice

切片

{{value|slice:"2:-1"}}

first

取第一个元素

{{ value|first }}

last

取最后一个元素

{{ value|last }}

join

使用字符串拼接列表。同python的str.join(list)。

{{ value|join:" // " }}

truncatechars

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

参数:截断的字符数

{{ value|truncatechars:9}}

date

日期格式化

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

safe

Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。

比如:

value = "<a href='#'>点我</a>"

{{ value|safe}}

3.标签

3.1 for 标签

#1、遍历每一个元素:
{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %}

#2、可以利用{% for obj in list reversed %}反向循环。

#3、遍历一个字典:
{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

#4、循环序号可以通过{{ forloop }}显示 
forloop.counter            当前循环的索引值(从1开始)
forloop.counter0           当前循环的索引值(从0开始)
forloop.revcounter         当前循环的倒序索引值(从1开始)
forloop.revcounter0        当前循环的倒序索引值(从0开始)
forloop.first              当前循环是第一次循环则返回True,否则返回False
forloop.last               当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop         本层循环的外层循环

#5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句
{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}

3.2 if 标签

# 1、注意:
{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,
在变量值为空、或者视图没有为其传值的情况下均为False

# 2、具体语法
{% if num > 100 or num < 0 %}
    <p>无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>凑活吧</p>
{% endif %}

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

3.3 with 标签

# with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,
# 在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
    {{ v }}
{% endwith %}

3.4 csrf_token 标签

# 当用form表单提交POST请求时必须加上标签{% csrf_token%},该标签用于防止跨站伪造请求
<form action="" method="POST">
    {% csrf_token %}
    <p>用户名:<input type="text" name="name"></p>
    <p>密码:<input type="password" name="pwd"></p>
    <p><input type="submit" value="提交"></p>
</form>
# 具体工作原理为:
# 1、在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签,
#该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
# 2、在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串,
# 对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份

3.5 注释标签

# 单行注释
{#   #}

# 多行注释
{% comment "Optional note" %}
    <p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}

4. 自定义过滤器和标签

1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

2、在app中创建templatetags模块(模块名只能是templatetags)

3、创建任意 .py 文件,如:my_tags.py

#my_tags.py
from django import template
register = template.Library() # 注意变量名必须为register,不可改变

#1、自定义过滤器
@register.filter
def my_multi_filter(v1 ,v2): # 自定义的过滤器只能定义最多两个参数,针对{{ value1 | filter_multi:value2 }},参数传递为v1=value1,v2=value2
    return  v1 * v2

#2、自定义标签
@register.simple_tag
def my_multi_tag(v1, v2): # 自定义的标签可以定义多个参数
    return v1 * v2


#3、自定义标签扩展之mark_safe
# 注释:我们可以用内置的标签safe来让标签内容有语法意义,如果我们想让自定义标签处理的结果也有语法意义,
# 则不能使用内置标签safe了,需要使用mark_safe,可以实现与内置标签safe同样的功能
from django.utils.safestring import mark_safe

@register.simple_tag
def my_input_tag(id, name):
    res = "<input type='text' id='%s' name='%s' />" % (id, name)
    return mark_safe(res)

4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py

<!-- HTML在使用 -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--必须先加载存有自定义过滤器和标签的文件-->
{% load my_tags %}

<!--salary的值为10,经过滤器my_multi_filter的处理结果为120-->
{{ salary|my_multi_filter:12 }}

<!--结果为2-->
{% my_multi_tag 1 2 %}

<!--
结果为一个input标签,该表的属性id="inp1" name="username"
注意:input的属性值均为字符串类型,所以my_input_tag后的两个值均为字符串类型
-->
{% my_input_tag "inp1" "username" %} 

</body>
</html>
  1. 在urls.py 和view.py 中 分布配置好才能生效
对比
#1、自定义过滤器只能传两个参数,而自定义标签却可以传多个参数

#2、过滤器可以用于if判断,而标签不能
{% if salary|my_multi_filter:12 > 200 %}
    <p>优秀</p>
{% else %}
    <p>垃圾</p>
{% endif %}

模板的导入和继承

  1. include
  2. extends
  3. block
母版:创建一个母版
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}自定义title名{% endblock %}
    </title>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            height: 50px;
            width: 100%;
            background-color: #919191;
            margin-bottom: 20px;
        }

    </style>

</head>
<body>
<div class="header"></div>

<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="list-group">
                {% block sidebar %}
                    <a href="#" class="list-group-item active">服装城</a>
                    <a href="#" class="list-group-item">美妆馆</a>
                    <a href="#" class="list-group-item">超市</a>
                    <a href="#" class="list-group-item">全球购</a>
                    <a href="#" class="list-group-item">闪购</a>
                    <a href="#" class="list-group-item">团购</a>
                {% endblock %}

            </div>
        </div>

        <div class="col-md-9">
            {% block content %}
                base.html页面内容
            {% endblock %}
        </div>
    </div>

</div>

</body>
</html>

在base.html打上block 标签,实现母版的复用

block
{% extends "base.html" %}

<!--用新内容完全覆盖了父模板内容-->
{% block title %}
    index页面
{% endblock %}


{% block sidebar %}
    <!--该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以在此基础上新增,否则就是纯粹地覆盖-->
    {{ block.super }}

    <!--在继承父模板内容的基础上新增的标签-->
    <a href="#" class="list-group-item">拍卖</a>
    <a href="#" class="list-group-item">金融</a>
{% endblock %}

{% block content %}
    <!--用新内容完全覆盖了父模板内容-->
    <p>index页面内容</p>
{% endblock %}

组件

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

{% include 'navbar.html' %}
总结
#1、标签extends必须放在首行,base.html中block越多可定制性越强

#2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写

#3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖

#4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
    {% block content %}
    ...
    {% endblock content %}  
#5、在一个模版中不能出现重名的block标签。

静态文件配置

在setting.py 中进行配置
STATIC_URL = '/static/' # 找到这一行,然后新增下述代码
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'statics'),# 获取静态文件在服务端的绝对路径
]
#STATIC_URL = '/static/'就是为静态文件的绝对路径起了一个别名,以后我们只需要用路径/static/即可

使用

一般不建议直接使用静态路径

static 的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--注意:必须先加载文件static.py-->
    {% load static %}
    <!--注意:此处的static是一个定义在static.py中的一个标签,名字与文件名一样而已,不要搞混-->
    <link rel="stylesheet" href="{% static 'css/my.css' %}">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="{% static 'img/rb.jpeg' %}" alt="">


{% load static %}
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script src="{% static 'js/my.js' %}"></script>

</body>
</html>

get_static_prefix 的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--注意:同样需要先加载文件static.py-->
    {% load static %}
    <!--使用标签get_static_prefix拼接路径-->
    <link rel="stylesheet" href="{% get_static_prefix %}css/my.css">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="{% get_static_prefix %}img/rb.jpeg" alt="">


{% load static %}
<script src="{% get_static_prefix %}js/jquery-3.3.1.min.js"></script>
<script src="{% get_static_prefix %}js/my.js"></script>

</body>
</html>
posted @ 2020-07-04 13:36  slzhao  阅读(134)  评论(0编辑  收藏  举报