Django的模板系统

Django模板中只有两种特殊符号:

{{  }}和 {% %}

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

变量{{ }}

{{ 变量名 }}

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

点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。

from django.shortcuts import render

# Create your views here.


def test(request):
    name = "goulonghui"
    age = 18
    t_lst = ["111", '222', '333']
    t_dic = {"name": "glh", "age": 18, "hobby_lst": ["妹子1", "妹子2", "妹子3"]}

    return render(request, 'test.html', {
        "name": name,
        "age": age,
        "t_lst": t_lst,
        "t_dic": t_dic
    })
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>{{ name }}</p>
<p>{{ age }}</p>
<p>{{ t_lst }}</p>
<p>{{ t_lst.0 }}</p>
<p>{{ t_lst.1 }}</p>

<ul>
    {% for foo in t_lst %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

<hr>
<p>{{ t_dic }}</p>
<p>{{ t_dic.name }}</p>
<p>{{ t_dic.hobby_lst }}</p>
<p>{{ t_dic.hobby_lst.0 }}</p>
<hr>
<ul>
    {% for foo in t_dic %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for foo in t_dic.keys %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for foo in t_dic.values %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for foo in t_dic.items %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for foo in t_dic.items %}
        <li>{{ foo.0 }}</li>
    {% endfor %}
</ul>
<hr>
<ul>
    {% for foo in t_dic.items %}
        <li>{{ foo.1}}</li>
    {% endfor %}
</ul>


</body>
</html>
test.html

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

  1. 在字典中查询
  2. 属性或者方法
  3. 数字索引

Filters

翻译为过滤器,用来修改变量的显示结果。

语法: {{ value|filter_name:参数 }}

'|'左右没有空格

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

小写

{{ value|lower }}

upper

大写

{{ 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"}}
<p>{{ t_lst|slice:"0:3" }}</p>  ['111', '222', '333']
<p>{{ t_lst|slice:"-1:-3:-1" }}</p>  [555, '444']
<p>{{ t_lst|slice:"-1:-3" }}</p>  []

first

取第一个元素

{{ value|first }}

last

取最后一个元素

{{ value|last }}

join

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

{{ value|join:" // " }}
<p>{{ t_lst|join:"*" }}</p>  111*222*333*444*555
<p>{{ t_dic|join:"*" }}</p>  字典默认为连接key name*age*hobby_lst 

<p>{{ t_dic.values|join:"+" }}</p>  glh+18+['妹子1', '妹子2', '妹子3']
<p>{{ t_dic.items|join:"-" }}</p>  ('name', 'glh')-('age', 18)-('hobby_lst', ['妹子1', '妹子2', '妹子3'])

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这段代码是安全的不必转义。

比如:

<p>{{ html_str }}</p>  <script>for(var i=0; i<5; i++){alert(666)}</script>
<p>{{ html_str|safe }}</p>

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

{{ value|safe}}

自定义filter

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

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

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

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

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

编写自定义filter:

#!/usr/bin/env python
# -*- coding:utf8 -*-

from django import template
register = template.Library()


@register.filter
def add_hello(value, arg='sfdsdfs'):
    return f"hello,{value},我传了个参数是{arg}"


@register.filter(name="Append")
def my_append(value, arg=None):
    if isinstance(value, list) and arg:
        value.append(arg)
        return value
    elif not arg:
        raise TypeError("append必须有一个参数")
    else:
        raise TypeError("非列表类型没有append方法")

使用自定义filter:

{# 先导入我们自定义filter那个文件 #}
{% load app01_filters %}


{% load app01_filters %}
<p>{{ t_lst.1|add_hello}}</p>
<p>{{ t_lst|Append:'sdf' }}</p>

 Tags{% %}

for

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

for循环可用的一些参数:

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

for ... empty

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

if,elif和else

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

当然也可以只有if和else

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

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

with

定义一个中间变量

{% with p1.dream as dream %}  # 相当于给p1.dream 其别名 dream,下面用的时候可以直接用dream,

{{dream}}

{% endwith %}

csrf_token

这个标签用于跨站请求伪造保护。(写这个后就不用注释csrf中间件也能接收post请求)

在页面的form表单里面写上{% csrf_token %}

注释

{# ... #}

注意:

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

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

ps:

a, b, c = 10, 5, 3
print(a>b>c)   #---> True

# 先判断a>b,为True, 再判断b>c,为True,  两次结果and


# 在js中:
var a=10;
var b=5;
var c = 3;

a>b>c   # ---> False

# 先判断a>b 为true, 即为1,再判断1>3,为false

# django中不支持连续判断

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

母板

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>{% block page_title %}{% endblock %}</title>
    <!-- Bootstrap -->
    <link href="/static/plugins/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/static/css/index_list.css">
    <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.min.css">


</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 pub_active %}{% endblock %}"><a href="/publisher/">出版社管理 <span class="sr-only">(current)</span></a></li>
                <li class="{% block book_active %}{% endblock %}"><a href="/book_list/">书籍管理</a></li>
                <li class="{% block aut_active %}{% 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>
</body>
</html>
母版是一个HTML页面

继承母版:

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

{% extends "public/base.html" %}

注意:要是没写在第一行,那么最上面的内容依然能显示,但是{% extends "public/base.html" %}下面的的除了块,其他都不能显示

块(block)

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

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

{% extends "public/base.html" %}

{% block page_title %}
    publisher_list
{% endblock %}

{% block pub_active %}
    active
{% endblock %}

{% block page_main %}
{#    非公共部分#}
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">出版社列表</h3>
        </div>
        <div class="panel-body">
            <div class="row">
                <div class="col-lg-3">
                    <div class="input-group">
                        <input type="text" class="form-control" placeholder="搜索">
                        <span class="input-group-btn"><button class="btn btn-primary" type="button"><i
                                class="fa fa-search"></i></button></span>
                    </div>
                </div>
                <div class="col-lg-1 pull-right">
                    <a href="/add_publisher/" class="btn btn-info"><i class="fa fa-plus fa-fw" aria-hidden="true"></i>添加</a>
                </div>
            </div>
            <p style="height: 5px"></p>
            <div class="table-responsive">
                <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th>序号</th>
                        <th>ID</th>
                        <th>NAME</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for publisher in publishers %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ publisher.id }}</td>
                            <td>{{ publisher.name }}</td>
                            <td>
                                <a class="btn btn-danger btn-sm" href="/edit_publisher/?id={{ publisher.id }}">
                                    <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>编辑
                                </a>
                                <a class="btn btn-warning btn-sm"
                                   href="/delete_publisher/?id={{ publisher.id }}">
                                    <i class="fa fa-trash fa-fw" aria-hidden="true"></i>删除
                                </a>
                            </td>
                        </tr>
                    {% empty %}
                        <tr>
                            <td colspan="5" class="text-center">没有查询到数据</td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
            {% load my_inclusion_tags %}
            {% my_tags 5 3 %}
        </div>
    </div>  
{% endblock %}

组件

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

{% include 'navbar.html' %}

静态文件相关

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

引用JS文件时使用:

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

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

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

使用get_static_prefix

<link rel="stylesheet" href="{% get_static_prefix %}plugins/bootstrap-3.3.7/css/bootstrap.min.css">

或者

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

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

自定义simpletag

和自定义filter类似,只不过接收更灵活的参数。

定义注册simple tag

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

使用自定义simple tag

{% load app01_demo %}

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

{# 注意了: 没有冒号 #}

inclusion_tag

多用于返回html代码片段

ex:分页效果

#!/usr/bin/env python
# -*- coding:utf8 -*-

# 自定制inclusion_tag
from django import template
register = template.Library()


@register.inclusion_tag("pagination.html")
def my_tags(total, page_num):
    return {"total": range(1, total+1), "page_num": page_num} # 此函数返回的就是那个"pagination.html"页面,将return中的结果也返回到了"pagination.html"页面中,可以用返回值做一些操作
{# 需要分页的地方使用 #}
{% load my_inclusion_tags %}
{% my_tags 5 3 %}  # 给自定义函数传参数
# 分页代码
<div class="pull-right"> <nav aria-label="..."> <ul class="pagination"> <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li> {% for num in total %} {% if num == page_num %} <li class="active"><a href="#">{{ num }}<span class="sr-only">(current)</span></a></li> {% else %} <li><a href="#">{{ num }}<span class="sr-only">(current)</span></a></li> {% endif %} {% endfor %} <li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li> </ul> </nav> </div>

 

posted @ 2018-07-30 20:17  Mr.GLH  阅读(234)  评论(0)    收藏  举报
Top↑