Django模板渲染

Posted fdsimin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django模板渲染相关的知识,希望对你有一定的参考价值。

django模板渲染

模板渲染,模板指的就是html文件,渲染指的就是字符串替换,将模板中的特殊符号替换成相关数据

基本语法

{{ 变量 }}
{% 逻辑 %}

 

变量使用

看示例

Views.py文件

def home(request):
    class A:
        def __init__(self):
            self.username = bob
        #如果方法需要在模板中使用,那么不能有其他参数
        def xx(self):  
            
            return bobxx

    info = {
        name: jack,
        hobby: [running, walking, reading],
        num: 100,
        d1:{aa:bb},
        l1:[11,22,{cc:dd}],
        a: A(),
    }

    return render(request, home.html, info)

home.html内容如下

重点:万能的据点号。通过点可以进行数据的索引取值,属性取值,取方法等等

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

</head>
<body>
<h2>{{ name }}</h2>

<ul>
    {% for i in hobby %}
        <li>{{ i }}</li>
    {% endfor %}

</ul>

<hr>
{{ num }}
<p>
    {{ l1.2.ss }}
</p>
<p>
    {{ d1.xx }}
</p>
<p>
    {{ a.username }}
</p>
<p>
    {{ a.xx }} <!-- 方法不能加括号,意味着不能穿参数,也就是说你后面定义的方法,不能有参数 -->
</p>

</body>

</html>

urls.py内容

url(r^home/, views.home),

 

过滤器

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

过滤器的语法:{{ value|filter_name:参数 }}

使用过滤器的注意事项

1. 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。

2. {{ sss|过滤器1:30|过滤器2.... }}

3. 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。

4. ‘|‘左右没有空格

 

 

内置过滤器

常用的内置过滤器示例

(1) default

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

{{ value|default:"nothing"}}

如果value没有传值或者值为空或者为False的话就显示nothing

(2) length

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

{{ value|length }}

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

(3) filesizeformat

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

{{ value|filesizeformat }}

如果 value 是 123456789,输出将会是 117.7 MB。

(4) slice

切片,如果 value="hello world",还有其他可切片的数据类型

{{value|slice:"2:-1"}}
(5) date

格式化,如果 value=datetime.datetime.now(),如果不想显示为UTC时间,将django的settings.py配置文件中的TIME_ZONE这一项修改一下,修改为TIME_ZONE = ‘Asia/Shanghai‘

比如,后台返回的数据为{‘value‘:datetime.datetime.now()}
?
对上面的数据进行格式化:{{ value|date:"Y-m-d H:i:s"}}

 关于时间日期的可用的参数(除了Y,m,d等等)还有很多,有兴趣的可以去查查看看。

(6) safe

xxs攻击,全称跨站脚本攻击    Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样你是不是可以搞一些坏事儿了,写个弹窗的死循环,那浏览器还能用吗,是不是会一直弹窗啊,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。

{‘a_tag‘:‘<a href="">百度</a>‘,}

渲染
<p>
    {{ a_tag|safe }} #生成标签效果
</p>
(7) truncatechars

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

参数:截断的字符数

{{ value|truncatechars:9}} #注意:最后那三个省略号也是9个字符里面的,也就是这个9截断出来的是6个字符+3个省略号,有人会说,怎么展开啊,配合前端的点击事件就行啦
(8) truncatewords

在一定数量的字后截断字符串,是截多少个单词。

例如:‘are you ok’,

{{ value|truncatewords:2}}  #上面例子得到的结果是 ‘are you...‘

(9) cut

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

{{ value|cut:‘ ‘ }}

如果value为‘i love you‘,那么将输出‘iloveyou‘.

(10) join

使用字符串连接列表,{{ list|join:‘, ‘ }},就像Python的str.join(list)

<p>{{ hobby|join:‘+‘ }}</p>

 

注意:模版渲染在浏览器渲染之前,模板渲染就是字符串替换,替换完成之后,将替换完的整体文件字符串返回给浏览器,浏览器再进行浏览器渲染,展示页面效果

 

标签

语法{% 标签 %}

(1) for循环标签

示例:

#循环列表
<ul>
    {% for xx in hobby %}
    <li>{{ xx }}</li>
    {% empty %}  #当hobby为空或者后台没有给这个数据,那么会显示empty下面的内容
        <h2>抱歉,没有查询到相关数据</h2>
    {% endfor %}
</ul>

#循环字典
<ul>
    {% for k,v in d1.items %}  <!-- 直接循环字典数据,那么是循环字典的key,循环d1.values,那么表示循环字典的值, 循环d1.items,那么k,v表示键和值-->
        <li>{{ k }}--{{ v }}</li>
    {% endfor %}

</ul>

#循环计数
<ul>
{% for i in l1 %}

{#    {{ forloop }}#}
    {% for h in hobby %}
        <li>{{ forloop.parentloop.counter }}--{{ forloop.revcounter0 }}---{{ h }}--{{ forloop.last }}</li>
    {% endfor %}

{% endfor %}
</ul>

forloop的解释
 注:循环序号可以通过{{forloop}}显示,必须在循环内部用 
forloop.counter            当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能
forloop.counter0           当前循环的索引值(从0开始)
forloop.revcounter         当前循环的倒序索引值(从1开始)
forloop.revcounter0        当前循环的倒序索引值(从0开始)
forloop.first              当前循环是不是第一次循环(布尔值)
forloop.last               当前循环是不是最后一次循环(布尔值)
forloop.parentloop         本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等
  
#反向循环
可以利用{% for obj in list reversed %}反向完成循环。
示例:
<ul>
    {% for xx in hobby reversed %}
    <li>{{ xx }}</li>
    {% endfor %}
</ul>

 

(2) if 标签

{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

{% if num > 100 or num < 0 %}
    <p>无效</p>  <!--不满足条件,不会生成这个标签-->
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}  <!--也是在if标签结构里面的-->
    <p>凑活吧</p>
{% endif %}

当然也可以只有if和else

{% if user_list|length > 5 %}  <!--结合过滤器来使用-->
  七座豪华SUV
{% else %}
    黄包车
{% endif %}

 

if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。

 

(3) with标签

使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的

例如:

注意等号左右不要加空格。

{% with total=business.employees.count %}
    {{ total }} <!--只能在with语句体内用-->
{% endwith %}

{% with business.employees.count as total %}
    {{ total }}
{% endwith %}

使用标签的注意事项

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

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

 

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的值。

 

自定义标签和过滤器

自定义过滤器

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

1、在app中创建templatetags文件夹(文件夹名只能是templatetags)

2、在templatetags文件夹中创建任意 .py 文件,如:mytag.py

3、在mytag.py文件中写上如下内容

from django import template

register = template.Library() #制作注册器,名字必须叫register

#过滤最多两个参数
@register.filter #注册过滤器,需要两个参数的
def add(v1, v2):  #v1表示管道符前面的,v2表示冒号后面的参数
    print(v1,v2) #100 50
    return v1 + v2

@register.filter #注册过滤器,需要一个参数的
def xxx(v1):  #v1表示管道符前面的
    print(v1) 
    return xxx

4、使用,在html文件中写上如下内容

{% load mytag %}  <!-- 首先通过load来加载一下mytag文件,不一定放在文件的开头,但是一定要放在使用过滤器的前面先进行引用 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>base页面</h1>
  <!--{% load mytag %} 放这里也是可以的-->  
<div>
    {{ num|add:50}}  <!-- 使用过滤器,和django内置过滤器用法一样,这里生成的是add函数的返回值 -->
</div>
<div>
    {{ num|xxx }}
</div>
<!--{% load mytag %} 放这里不行-->  

</body>

</html>

 

自定义标签

过程:

1、在app中创建templatetags文件夹(文件夹名只能是templatetags)

2、在templatetags文件夹中创建任意 .py 文件,如:mytag.py

3、在mytag.py文件中写上如下内容

from django import template

register = template.Library() #制作注册器,名字必须叫register

@register.simple_tag
def atag(v1,v2): #没有参数个数限制
    print(v1,v2)
    return v1 + v2

4、使用,在html文件中写上如下内容

{#{% load mytag %}#}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>base页面</h1>
{% load mytag %}

<div>
    {% atag ‘a‘ ‘b‘ %}  <!-- 注意,是{%%} 来包裹使用,先是标签名称然后空格写参数,参数之间也是空格分隔的 -->
</div>

</body>

</html>

 

模板继承

将一些页面公共的部分,可以抽离出来单独做成一个html页面,使用这些公用部分的其他html文件,只需要继承一下它就可以了,具体使用流程如下:

1 创建公用模板,比如内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            padding: 0;
            margin: 0;
        }
        {% block css %}
        .nav{
            height: 60px;
            background-color: green;
        }
        {% endblock %}
        .nav a{
            color:white;
            text-decoration: none;
        }
        .left-menu{
            width: 30%;
            background-color: rgba(0,0,0,0.5);
            float:left;
        }
        .menu .menu-title{
            text-align: center;
        }
        .main{
            float: right;
            width: 65%;
            height: 300px;
            border: 1px solid red;
        }
    </style>
</head>
<body>

<div class="nav">
    <a href="/xx1/">首页</a>
    <a href="/person/">个人中心</a>
    <a href="/detail/">详情页</a>
</div>
<div class="left-menu">
    <div class="menu">
        <div class="menu-title">菜单1</div>
        <div class="menu-body">
            <div class="item">包子</div>
            <div class="item">馒头</div>
            <div class="item">凉皮</div>
            <div class="item">面条</div>
        </div>
        <div class="menu-title">菜单2</div>
        <div class="menu-body">
            <div class="item">排骨藕汤</div>
            <div class="item">粉蒸肉</div>
            <div class="item">腊鱼块</div>
            <div class="item">灌肠</div>
        </div>
    </div>
</div>
<div class="main">
    {% block content %}
    公共页面
    {% endblock %}
</div>

</body>
{% block js %}
    
{% endblock %}

</html>

2 将来如果说继承公用模板的html文件中需要修改公用模板中的一些内容,那么需要在公用模板中预留一些钩子,钩子的写法如下

{% block content %}  #block 后面的块名称随便起
公共页面
{% endblock %}
#也可以这样写 {% endblock content %}  #endblock指定名称

3 继承公用模板需要在html文件中写如下内容:

{% extends ‘xx.html‘ %}  <!-- 需要先继承一下公用模板,写法就是extends ‘公用模板文件名称‘,注意,必须写在第一行 -->

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    <h1>首页</h1>
{% endblock %}

4 在使用公用模板的其他html文件中,如果需要更改公用模板里面的内容,只需要在html文件中写上相同的钩子,钩子里面写上自定义的内容,写法如下

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    <h1>首页</h1>
{% endblock %}

注意事项:

  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作,模板渲染的时候django都不知道你在干啥。

  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。

  • 如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。

  • {{ block super }}的使用,在子模板中也展示出父模板原来钩子中的内容

{% block content %}

    <h1>首页</h1>
    {{ block.super }}
{% endblock %}

为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:

{% block content %}
...
{% endblock content %}  

在大型模版中,这个方法帮你清楚的看到哪一个  {% block %} 标签被关闭了。

 

不能在一个模版中定义多个相同名字的 block 标签。

#两个block都叫content,这种写法是不对的
{% block content %}

    <h1>首页</h1>
    {{ block.super }}
{% endblock %}
{% block content %}

    <h1>首页</h1>
    {{ block.super }}
{% endblock %}

 

 

 

以上是关于Django模板渲染的主要内容,如果未能解决你的问题,请参考以下文章

如何更新 django 模板中的渲染变量?

如何让 liveserver 渲染 django 模板?

Django - 渲染模板并通过 AJAX 传递它们

django-缓存的三种应用

Django 渲染模板 `500.html` 而不是 `404.html`

如何在 Django 中显式重置模板片段缓存?