Django框架
Django模板常用的过滤器
•在模板中,很多时候需要对传递过来的数据进行处理之后才能使用,在Python中一般是通过函数来完成对数据的处理,在Django框架的模板中,则是通过过滤器来实现对数据的处理
•过滤器是通过|
来使用的,用法为 视图函数变量 | 模板过滤器:“参数”
,其中参数为可选项
add过滤器
•将传递进来的参数添加到原来的参数上面,add过滤器
会尝试将值和参数转换成整形然后进行简单相加,得到最好的值
•如果类型转换失败,则会将数值和参数进行拼接
•如果是参数是字符串,那么会拼接成字符串
•如果是参数列表,那么会拼接成一个列表
代码测试如下:
•首先创建项目django_filter
,再创建名为front的app,然后在项目目录下的settings.py (django_filter/settings.py) 进行模板(templates)的路径配置:
import os
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',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
•项目目录下的urls.py文件:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('front.urls')),
]
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request): #定义视图函数
context = {
'number': 8,
'char': '88',
'li1': [8, 9],
'li2': [6, 2],
}
return render(request, 'index.html', context=context)
•在项目目录下新建templates目录,又在templates目录下新建index.html模板文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>首页</p>
<p>原始数字:{{ number }}</p>
<p>数字加2:{{ number | add:'2' }}</p>
<p>数字加a:{{ number | add:'a' }}</p>
<p>字母加a:{{ char | add:'a' }}</p>
<p>列表相加:{{ li1 | add:li2 }}</p>
</body>
</html>
•front app下新建urls,py文件进行视图函数路由的配置 如下:
from django.urls import path
from . import views
urlpatterns = [
path('add/', views.index)
]
网页显示如下;
•由上面可以看出,当不同类型的变量进行匹配相加,如果两个变量相加没有任何意义,就会返回空字符串,不会报错
cut过滤器
•用于移除变量值中所有指定的字符串,类似于Python语法中的的replace()方法
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>{{ 'Hello World' | cut:'o' }}</p>
</body>
</html>
网页显示如下:
date过滤器
•用于将一个日期转换成特定格式的字符串
具体的字符和含义如下表所示:
格式字符 | 含义 | 范围和举例 |
---|---|---|
Y | 四位数字的年份 | 2020 |
m | 两位数字的月份 | 01–12 |
n | 月份,1-9前面没有0前缀 | 1–12 |
d | 两位数字的日 | 01–31 |
j | 日,1-9前面没有0前缀 | 1–31 |
h | 小时,12小时格式的,1-9前面有0前缀 | 01–12 |
g | 小时,12小时格式的,1-9前面没有0前缀 | 1–12 |
H | 小时,24小时格式的,1-9前面有0前缀 | 01–23 |
G | 小时,24小时格式的,1-9前面没有0前缀 | 1–23 |
i | 分钟,1-9前面有0前缀 | 00–59 |
s | 秒,1-9前面有0前缀 | 00-59 |
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>原始时间格式:{{ now }}</p>
<p>自定义时间格式1:{{ now | date:'Y/m/d H:i:s' }}</p>
<p>自定义时间格式2:{{ now | date:'Y/n/j g:i:s' }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from datetime import datetime
from django.shortcuts import render
def index(request):
context = {
'number': 8,
'char': '88',
'li1': [8, 9],
'li2': [6, 2],
'now': datetime.now()
}
return render(request, 'index.html', context=context)
网页显示如下:
default过滤器
•如果传递到模板中的变量被判断为False,比如空字符串" "、空列表[]、空字典{}、空值None等在条件判断中为False的值
,可以使用default过滤器提供的默认值代替原来的空值
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>原始时间格式:{{ now }}</p>
<p>信息info:{{ info|default:'信息正在完善中请稍等!!'}}</p>
<p>自定义时间格式:{{ now | date:'Y/m/d H:i:s'|default:'暂未设置时间' }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from datetime import datetime
from django.shortcuts import render
def index(request):
context = {
'number': 8,
'char': '88',
'li1': [8, 9],
'li2': [6, 2],
'info': '',
'now': None,
}
return render(request, 'index.html', context=context)
网页显示如下:
可以看出:
•在传递的变量被判定为空值(Flase)
时,就会显示指定的默认值
•同时,在有意义的前提下,多个过滤器可以自由结合使用
first和last过滤器
•first过滤器返回列表、元组、字符串中的第一个元素,last过滤器返回列表、元组、字符串中的最后一个元素
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>图书首页</p>
<p>第一本书:{{ books|first }}</p>
<p>最后一本书:{{ books|last }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'books': ['Python头秃日记', 'Java冲冲冲', 'PHP天下第一'],
}
return render(request, 'index.html', context=context)
网页显示如下:
floatformat过滤器
•使用四舍五入的方式格式化一个浮点类型变量,floatformat过滤器没有传递任何参数时,会默认在小数点后保留一个小数,没有传递任何参数并且小数后面全是0时,只会保留整数,传递一个参数时,会保留指定的小数位数
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<ul>
<li>{{ 3.14|floatformat }}</li>
<li>{{ 3.1415|floatformat }}</li>
<li>{{ 3.1415926|floatformat:4 }}</li>
<li>{{ 3.00000|floatformat }}</li>
<li>{{ 3.00000000|floatformat:4 }}</li>
</ul>
</body>
</html>
网页显示如下:
join过滤器
•类似于Python中的join()方法
,将列表、元组、字符串中的元素用指定的字符进行拼接
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>首页</p>
<p>当前日期:{{ date | join:'--' }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
}
return render(request, 'index.html', context=context)
网页显示如下:
safe过滤器
之前已经用到过,它是用来标记一个字符串是安全的,会关掉这个字符串的自动转义,如果变量是一个不包含任何特殊字符的普通字符串,会把字符串正常输入,如果value是html类型代码
,会将html代码渲染到浏览器中
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>日期:{{ date | join:'--' }}</p>
<p>普通字符串:{{ info }}</p>
<p>安全字符串:{{ info | safe }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': '<a href="https://blog.csdn.net/qq_45261963?spm=1010.2135.3001.5343">个人博客首页</a>'
}
return render(request, 'index.html', context=context)
网页显示如下:
slice过滤器
slice过滤器,类似于Python中的切片操作,对列表、字符串等进行切片,需要传递整型参数
假如为下标名为index
,则不同的方式意义上有所不同,index范围是从1开始到被切片对象的长度
index和 : index
的含义一致,均为从1到index对应的元素(包括该元素)
index:
为index对应的元素之后的元素(不包括该元素)
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>日期:{{ date | slice:'1' }}</p>
<p>日期:{{ date | slice:':1' }}</p>
<p>日期:{{ date | slice:'1:' }}</p>
<p>日期:{{ date | slice:'2' }}</p>
<p>日期:{{ date | slice:':2' }}</p>
<p>日期:{{ date | slice:'2:' }}</p>
<p>字符串:{{ info | slice:'3' }}</p>
<p>字符串:{{ info | slice:':3' }}</p>
<p>字符串:{{ info | slice:'6:' }}</p>
<p>字符串:{{ info | slice:'6' }}</p>
<p>字符串:{{ info | slice:':9' }}</p>
<p>字符串:{{ info | slice:'9:' }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2020', '09', '05'],
'info': 'hello world'
}
return render(request, 'index.html', context=context)
网页显示如下:
striptags标签
用于删除字符串中所有的html标签
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>首页</p>
<p>个人信息:{{ info | striptags }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': '<a href="https://blog.csdn.net/qq_45261963?spm=1010.2135.3001.5343">个人博客首页</a>'
}
return render(request, 'index.html', context=context)
网页显示如下:
truncatechars过滤器
如果给定的字符串长度超过了truncatechars过滤器指定的长度,就会对字符串进行切割,并且会拼接三个点 …
来作为省略号 表示后面内容被省略了
如果没有超过truncatechars过滤器指定的长度,则不做任何处理
这在网站标题显示中应用很广泛
代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>前台首页</p>
<p>信息1:{{ info | truncatechars:'10' }}</p>
<p>信息2:{{ info | truncatechars:'50' }}</p>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': 'Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计'
}
return render(request, 'index.html', context=context)
网页显示如下:
其他常见过滤器
其他常用过滤器如下表:
过滤器 | 作用 | 举例 |
---|---|---|
length | 获取一个列表、元组、字符串、字典的长度 | { value|length }} |
lower | 将变量中所有的字符全部转换成小写 | {{ value|lower }} |
upper | 将指定的字符串全部转换成大写 | {{ value|upper }} |
random | 在给定的列表、字符串、元组中随机选择一个值 | {{ value|random }} |
•更多过滤器可以查看Django中文文档https://docs.djangoproject.com/zh-hans/2.0/或者查看Django源码django.template.defaultfilters
模板结构优化
在实际项目中,网页界面都具有一定的结构,包括头部、主体内容、底部内容等部分,如Python菜鸟教程一样:
每个网页都有一样的头部信息,和底部信息
现在模拟如上情况,代码测试如下:
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>发现</li>
<li>关注</li>
<li>消息</li>
</ul>
<h1>前台首页</h1>
<p>信息:{{ info }}</p>
</body>
</html>
•模板目录下新建info.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>发现</li>
<li>关注</li>
<li>消息</li>
</ul>
<h1>个人中心</h1>
</body>
</html>
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': 'Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计'
}
return render(request, 'index.html', context=context)
def info(request):
return render(request, 'info.html')
•front app下视图urls.py文件如下:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('info/', views.info, name='info'),
]
网页显示如下:
可以看到,前台首页和个人中心页都有发现、关注、消息等栏目,但是存在一些问题:
•页面较多时HTML代码重复多、复用性较低
•在需要修改时,需要对每个HTML文件进行修改,可维护性较差
上述情况,有两种方法解决:
•引入模板
•模板继承
引入模板
有时候一些HTML代码在许多模板文件中都会用到,如果使用大量重复代码不符合项目的规范,一般可以把重复性的代码抽取出来,就类似于Python中的函数一样,以后想要使用这些代码的时候,就通过include标签
包含进来即可使用
•模板目录下新建header.html文件保存公共的头部代码:
<ul>
<li>发现</li>
<li>关注</li>
<li>消息</li>
</ul>
•模板index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% include 'header.html' %}
<h1>前台首页</h1>
<p>信息:{{ info }}</p>
</body>
</html>
•模板info.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% include 'header.html' %}
<h1>个人中心</h1>
</body>
</html>
•效果与之前代码一样
include标签
寻找路径的顺序和render
渲染模板是一样的
默认include标签引用模板时会自动使用主模板中的上下文,也即可以自动使用主模板中的变量
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': 'Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计'
}
return render(request, 'index.html', context=context)
def info(request):
context = {
'username': 'Ycx'
}
return render(request, 'info.html', context=context)
•模板header.html文件如下:
<ul>
<li>发现</li>
<li>关注</li>
<li>消息</li>
<li>{{ username }}</li>
</ul>
网页显示如下:
由上可得,如果在视图函数中传递了变量,模板中也会进行渲染
模板继承
在模板的结构优化方面,模板继承
比引入模板的灵活性更高、应用更广泛
Python中的类:
在父类中可以先定义好一些变量和方法,然后在子类中可以调用并使用父类方法
模板继承类似于Python,也可以在父模板中先定义好一些子模板需要用到的代码,然后子模板直接继承,同时因为子模板有需要自己实现的代码,因此需要在父模板中定义一个block接口
,用于子模板的扩展
•front app下视图views.py文件如下:
from django.shortcuts import render
def index(request):
context = {
'date': ['2021', '03', '22'],
'info': 'Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计'
}
return render(request, 'index.html', context=context)
def info(request):
context = {
'username': 'Ycx'
}
return render(request, 'info.html', context=context)
def book(request):
return render(request, 'book.html')
•front app下视图urls.py文件如下:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('info/', views.info, name='info'),
path('book/', views.book, name='book'),
]
•模板目录下新建base.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}前台{% endblock %}</title>
</head>
<body>
<ul>
<li>发现</li>
<li>关注</li>
<li>消息</li>
<li>{{ username }}</li>
</ul>
{% block content %}
<h1>父模板</h1>
{% endblock %}
<footer>
网站底部
</footer>
</body>
</html>
上述base.html
定义好一个基础的html框架,然后定义好需要的block接口
,让子模板根据具体需求来实现,并通过extends标签
来引用父类中的方法
•模板目录下新建book.html文件如下:
{% extends 'base.html' %}
{% block title %}
图书
{% endblock %}
<h1>block外:图书首页</h1>
{% block content %}
<h1>block内:图书首页</h1>
{% endblock %}
网页显示:
由上可以看出:
子模板中的代码必须放在block中,否则不会被渲染
如果在父模板的block中定义了内容、而子模板不重写,则直接使用父模板中的内容,如果子模板进行重写,则渲染重写后的内容
如果需要在某个block
中使用父模板的内容,可以使用{{ block.super }}
来实现继承
•模板目录下book.html文件如下:
{% extends 'base.html' %}
{% block title %}
图书
{% endblock %}
<h1>block外:图书首页</h1>
{% block content %}
<h1>block内:图书首页</h1>
{{ block.super }}
{% endblock %}
网页显示:
注意
extends标签
必须放在整个模板文件的最前面
在定义block时,除了在block开始的地方定义block的名字,还可以在block结束的地方定义,如{% block title %}{% endblock title %}
。在大型模板中使用显得尤其有用,可以清晰看到block所包含的范围
加载静态资源文件
网页中,一般不仅只有一个html框架,还需要css样式文件、js执行文件和图片等,因此需要实现在DTL中加载静态文件
在DTL中,使用static标签
来加载静态文件。要使用static标签,首先需要{% load static %}
具体步骤如下:
•(1)在项目目录下的settings.py文件中,注册需要加载静态资源的app 确保django.contrib.staticfiles
已经添加到settings.INSTALLED_APPS
中
项目目录下的settings.py文件如下:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'front',
]
•(2)确保在settings.py
中设置了STATIC_URL
STATIC_URL
是Django默认实现,如下:
STATIC_URL = '/static/'
•(3)在已经注册了的app下创建static目录,然后再在static文件夹
下创建一个名为当前app名的目录,再把静态文件放到这个目录下
这里就是在front目录下创建static目录
,用于保存只会在front app中用到的静态资源文件
•模板目录下info.html文件如下:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% include 'header.html' with username='Jackson' %}
<h1>个人中心</h1>
<img src="{% static 'monkey.png' %}" alt="猴子">
</body>
</html>
网页显示:
在app下的static目录下再创建名为app名的目录,是因为只在app下创建static目录并将静态资源文件保存到其中,会出现问题:
•如果直接把静态文件放在static文件夹下,那么在模板加载静态文件时按照INSTALLED_APPS
中注册app的顺序依次查找对应的资源文件,如果在多个app之间有同名的静态文件,就可能会产生混淆而加载错误
•而在static文件夹下加了一个同名app文件夹,在模板中加载的时候就是使用app/monkey.png
,这样就可以避免产生混淆
可以看到,总体上,静态资源文件加载有两种方式:
•app内部资源文件加载:
•在每个app内部建立static目录,并再创建名为app名的子目录,同时在settings.py中配置STATIC_URL,查找资源文件时会根据安装的app的顺序进行查找
•项目资源文件加载:
•在项目目录下创建static目录用于保存公共资源文件,并在settings.py中配置STATICFILES_DIRS
。也可以在static目录下创建对应于每个app的子目录,用于保存每个app的资源文件
建议使用第二种方式,项目结构更加合理,也更方便管理静态资源文件