Django(三)模板

本文详细介绍了Django模板的各个方面,包括模板语法、模板变量、控制结构如if和for,以及模板继承和包含。还讨论了自定义过滤器和标签的创建方法,以及模板查找机制。同时,解释了如何使用模板上下文处理器使变量在所有模板中可用。
摘要由CSDN通过智能技术生成

1 简介

1.1 什么是模板

视图函数的作用是生成请求的响应,这种响应通常就是用户所看到的html网页。模板就是带有模板语法({{ }}, {% %})的html文件,它能接收视图函数传递的变量,通过模板引擎,模板被渲染成html页面。

1.2 语法

在模板中,使用{{ }}结构表示一个变量,它是一种特殊的占位符,告诉模板引擎,这个位置的值从渲染模板时传入的变量获取;使用{% %}结构渲染标签(控制结构)。

1.3模板查找机制

模板一般放在应用下的templates文件夹,Django的模板渲染引擎会自动查找所有应用下这个文件夹,直到找到指定的模板,因此如果不同应用下有同名的模板,Django很可能找错。因此建议的做法是,在每个应用下的templates文件夹下创建以应用名命名的文件夹,将与该应用相关的模板放在这个文件夹中,就像这样:app/templates/app/XXX.html。当视图函数返回render响应时,相应地在模板名称前加上app的名字,就像这样:return render('app/XXX.html')

2 模板变量

2.1 深度查询

Django的模板引擎能识别python中所有类型的变量,对于列表、字典、和对象这些复杂的变量,我们可以通过万能的句点法(深度查询)来访问集合或对象,比如:

<p>对列表取值:{{ list.index }}</p>
<P>对字典取值: {{ dict.key }}</P>
<P>访问对象的属性: {{ obj.attr }}</P>

2.2 使用变量过滤器

作用:修改变量在模板中的显示
格式:{{ var|filter: arg }} 注意,过滤器函数默认接收变量,除此之外,最多只能接收一个参数

看个栗子:
1.我们在视图函数中定义一些变量,通过locals()全部传入模板渲染

def index(request):
    string = 'he l lo'
    day = datetime.datetime.now()
    l = []
    post = "this is my post, it's very very very long"
    k = ['cat', 'dog', 'pig']
    size = 12345678
    return render(request, 'blog/index.html', locals()) # 注意,blog前不要加/
    # locals() 将视图中的所有变量对应到模板中的变量

2.在模板中应用过滤器来修改变量

<h1>filter过滤器效果!</h1>
<h3>{{ string }} --> {{ string|cut:" " }}  剔除指定字符串</h3>
<h3>{{ day }} --> {{ day|date:"Y-m-d" }}  格式化日期</h3>
<h3>{{ l }} --> {{ l|default:"查询结果为空" }} 当集合为空时,设置默认显示,比如数据库查询结果为空时,我们自定义前端的提示信息</h3>
<h3>{{ post }} --> {{ post|truncatewords:6 }}  截断指定数量的单词,可用于显示文章摘要</h3>
<h3>{{ k }} --> {{ k|join:", " }}  拼接列表</h3>
<h3>{{ size }} --> {{ size|filesizeformat }}  显示友好的文件大小</h3>

3.浏览器显示效果:
这里写图片描述

4.变量过滤器一览

过滤器说明
add给变量加上一个值
addslashes给变量中的引号前加/斜线
capfirst首字母大写
lower转换为小写
truncatewords:30截断指定数量的单词,可用于显示文章摘要
join用指定字符拼接列表
default如果变量为空或false,使用默认值
length显示字符串/列表的长度
filesizeformat显示易读的文件大小
date格式化日期字符串
cut从字符串中移除指定的字符
safe渲染值时不转义。出于安全考虑,模板引擎会转义所有的变量。如果确实需要显示变量中的html代码,就可以使用safe过滤器。不要对不可信的变量使用safe过滤器,比如用户提交的表单中输入的文本,可能包含攻击代码。

过滤器也支持链式操作:
{{ var|filter1|filter2 }}

5.更多过滤器的使用,请参考 built-in filter reference

2.3 自定义过滤器和标签

2.3.1 自定义过滤器

过滤器本质就是一个函数,只需要如下几步,我们也可以定制自己的过滤器
1. 将当前应用添加到settings.py的INSTALLED_APPS 列表中
2. 在项目的应用文件夹下新建一个包,命名为templatetags
3. 在刚刚新建的包下写一个脚本,比如my_filter.py:

```
from django import template
register = template.Library()
# 导入template 并实例化一个对象,命名为 register

@register.filter  # 装饰自定义函数为过滤器
def num_to_char(x): # 自定义函数,将数字转为字符
    return chr(x)
```

4. 在模板的<head>标签内中导入自定义的过滤器(使用前导入就行,不一定非要在<head>内):{% load my_filter %} 。另外,发现一个问题,自定义过滤器导入后,自带的过滤器可能工作不正常,具体原因不明,有知道的伙伴可以分享下。
5. 重启服务,你就可以使用自定义的过滤器了

2.3.2 自定义标签

自定义标签的流程和自定义过滤器是相同的,只是装饰器修改为@register.simple_tag
另外在使用格式上,自定义标签是这样:
{% func var [arg1] [arg2] ... [argn] %}
二者的其他差异:
1. 过滤器除了接收变量本身,最多可以额外接收一个参数,而自定义标签无限制
2. 过滤器可以配合其它标签使用,比如if控制语句:

```
{% if var|filter %}
    do something
```
但是自定义标签不能这样使用。


补充:自定义标签的另一种形式 inclusion_tag:

  1. 应用下新建templatetags目录,新建脚本custom_tag.py,通过inclusion_tag自定义标签

    from django.template.library import Library
    
    register = Library()
    
    
    @register.inclusion_tag('sample.html')
    def get_result(x):
    
        print('do something')
    
        return {'content': 'XXX', 'comments': ['aa', 'bb', 'cc']}

    说明:

    • inclusion_tag接收一个模板路径,这里是”sample.html”,并将函数的返回值拿到模板中渲染
    • “sample.html”模板的渲染结果,返回给调用该自定义标签的模板中,即步骤3的模板。
  2. 定义”sample.html”模板:

    <div id="body">
        {{ content }}
    </div>
    <ul id="comment_list">
        {% for comment in comments %}
            <li>{{ comment }}</li>
        {% endfor %}
    </ul>
  3. 调用自定义标签:

    {% load custom_tag %}
    
    <div id="article">
        {% get_result x %}
    </div>

3 控制结构

Django的模板引擎提供了多种控制结构,用来改变模板的渲染流程。

3.1 if语句

{% if user %}
    Hello, {{ user }}!
{% else %}
    Hello, {{ Stranger }}!
{% endif %}

3.2 for循环

渲染从数据库取出的一组评论,使用for循环可以实现这一需求

<ul>
    {% for comment in comments %}
        <li>{{ comment }}</li>
    {% endfor %}
</ul>

3.2.1 forloop变量

forloop用在for循环内,配合if语句,可以用来控制循环:
1. forloop.counter 索引,从1开始,可用于显示清单中条目的序号
2. forloop.counter0 索引,从0开始
3. forloop.revcounter 索引,倒序到1
4. forloop.revcounter0 索引,倒序到0
5. forloop.first 当第一次循环时,值为True
6. forloop.last 当第一次循环时,值为False

看个栗子:

<ul>
    {% for comment in comments %}
        <!-- 如果是第一条评论,就给它加某种样式 -->
        {% if forloop.first %}
            <li class="first">
        {% else %}
            <li>
        {% endif %}
                {{ comment }}
            </li>
    {% endfor %}
</ul>

3.2.2 for … empty

for循环可以可以接受一个{% empty %}从句,如果循环的对象为空,将显示{% empty %}从句下的内容:

<ul>
{% for comment in comments %}
    <li>{{ comment }}</li>
{% empty %}
    <li>No comments yet!</li>
{% endfor %}
</ul>

3.3 代码重用

3.3.1 模板继承

模板继承(extends)类似Python中的类继承。它允许我们重用模板中相同的部分,定制不同的部分。首先,创建一个名为base.html的基模板:

<html>
<head>
    {% block head %}
    <title>{% block title %}Title{% endblock %}</title>
    {% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>

block标签定义的块可以在衍生模板中修改,并且每个block标签都有名字。这里,我们只是简单定义了head, title(因为每个页面都应该显示一个不同title), body的块。注意,title包含中head中。下面我们来写一个基模板的衍生模板:

{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block head %}
    {{ block.super }}
    <style>
    </style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}}

{% extends 'base.html' %}继承指令放在首行,声明该模板衍生自base.html。我们在衍生模板中重定义了三个block的内容,模板引擎会根据block名字,将其插入适当的位置。另外,通过{% block.super %},可以重用原来block中的内容,以便在其基础上添加内容。

3.3.2 模板包含

需要在多处重复使用的模板代码片段可以写在单独的文件,再包含(include)在要用的模板中,以避免重复:
{% include 'common.html' %}

3.4 其它标签

  • {% url %} 通过视图函数别名,生成url绝对路径,它还可以接收路由分组的参数: {% url 'name' v1 v2 %}
  • {% with %} 用更简单的变量名替代复杂的变量名
{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}
<!-- 这里变量business.employees.count赋值给total, 方便后续使用;当然也可以采用下面的写法 -->
{% with business.employees.count as total %}
...
{% endwith %}
  • {% verbatim %} 告诉模板引擎,不要渲染这个标签内的内容
{% verbatim %}
    {{ 我就是要显示两个花括号! }}
{% endverbatim %}
  • {% load %} 载入自定义的模板标签,记住,目标不加引号

更多标签,请参考官网built-in-tag-reference

模板上下文处理器

令某些变量在所有模板中可用,比如,网站的顶部分类菜单,在很多页面中都是相同的。

settings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                # ...
                'app.views.get_funcs', # 视图加入上下文处理器列表
            ],
        },
    },
]
FUNCTIONS = [
    (1,"园子"),
    (2,"随笔"),
    (3,"新闻"),
    (4,"博文"),
]

views.py

def get_funcs(request):
    return ({"funcs": settings.FUNCTIONS})

template: funcs变量在所有模板中可用

{% for func in funcs %}
    <li><a href="#">{{ func.1 }}</a></li>
{% endfor %}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值