在Django框架中,模板是可以帮助开发者快速生成呈现给用户页面的工具
模板的设计方式实现了我们MVT中VT的解耦(M: Model,V:View,T:Template),VT有着N:M的关系,一个V可以调用任意T,一个T可以供任意V使用。
MVC: M: Model,V:View界面,Controller控制器
模板处理分为两个过程
加载HTML
渲染数据 render()
模板主要有两个部分
HTML静态代码
模板语言,动态插入的代码段(挖坑,填坑)
{{ name }} 如果你不给name传值,这个坑就什么都没有
模板中的动态代码段除了做基本的静态填充,还可以实现一些基本的运算,转换和逻辑
静态页面:页面数据是本地固定的
动态页面:页面数据来源于后台服务器
模板中的变量:视图传递给模板的数据,遵守标识符规则
语法: {{ var }}
如果变量不存在,则插入空字符串
方法不能有参数,不能带括号()
{{ str }}
{{ str.upper }}
{{ str.isdigit }}
{{ dict.key }}
列表,使用索引,不允许负索引
items= ['apples','bananas', 'carrots']
{{ items.2 }}
模板中的标签
语法 {% tag %]
作用
1. 加载外部传入的变量
2. 在输出中创建文本
3,控制循环或逻辑
if 语句:
格式:
if单分支
{% if 表达式 %}
语句
{% endif %}
if双分支
{% if 表达式 %}
语句
{% else %}
语句
{% endif %}
if多分支
{% if 表达式%}
语句
{% elif 表达式%}
语句
{% else %}
语句
{% endif %}
判断true或false
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
使用 and or not
{% if athlete_list and coach_list %}
<p>Both athletes and coaches are available.</p>
{% endif %}
{% if not athlete_list %}
<p>There are no athletes.</p>
{% endif %}
(% if athlete_list or coachl_list %}
<p>There are some athletes or some coaches.</p>
{% endif %}
使用 in和not in,
{% if "bc" in "abcdef" %}
This appears since "bc" is a substring of "abcdef"
{% endif %}
{% if user not in users %}
If users is a list, this will appear if user isn't an element of the list.
{% endif %}
for 语句
{% for 变量 in 列表 %}
语句1
{% empty %}
语句2
{% endfor %}
当列表为空或不存在时执行empty之后的语句
{{ forloop.counter}} 表示当前是第几次循环,从1数数
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
{{ forloop.counter0}}表示当前是第几次循环,从0数数
{{ forloop.revcounter}}表示当前是第几次循环,倒着数数,到1停
[[ forloop.revcounter0}}表示当前第几次循环,倒着数,到0停
[[ forloop.first }} 是否是第一个 布尔值
{% for object in objects %}
{% if forloop.first %}
<li class="first">
{% else %}
<li>
{% endif %}
{{ object }}</li>
{% endfor %}
{{ forloop.last }} 是否是最后一个 布尔值
{% for link in links %}
{[ link }}{% if not forloop.last %} | {% endif %}
{% endfor %}
forloop 表示当前循环
forloop.parentloop 表示当前循环的父循环,
返回值的是{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 3,
'revcounter0': 2, 'first': True, 'last': False}
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}
<td>City #{{ forloop.counter }}
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
注释:
单行注释
{# 被注释掉的内容 #}
多行注释
{% comment %}
内容
{% endcomment %}
过滤器
{{ var|过滤器 }}
作用:在变量显示前修改
add {{ value|add:2 }}
没有减法过滤器,但是加法里可以加负数
{{ value|add:-2 }}
lower
{{ name|lower }}
upper
{[ my_list|first|upper }}
截断:
{{ bio|truncatechars:30 }}
过滤器可以传递参数,参数需要使用引号引起来
比如join: {{ students|join:'=' }}
默认值:default,格式 {{var|default:value}}
如果变量没有被提供或者为False,空,会使用默认值
根据指定格式转换日期为字符串,处理时间的
就是针对date进行的转换
{{ dateVal | date:'y-m-d' }}
HTML转义
将接收到的数据当成普通字符串处理还是当成HTML代码来渲染的一个问题
渲染成html:
{{ code|safe }}
关闭自动转义
{% autoescape off %}
code
{% endautoescape %}
打开自动转义转义
{% autoescape on %}
code
{% endautoescape %}
模板继承
extends继承,写在开头位置
{% extends '父模板路径' %}
block:
{% block XXX %}
code
{% endblock %}
include: 加载模板进行渲染
{% include '模板文件' %}
{{ block.super }} : 获取父模板中block中的内容
根路由Day02MyDjangoPro02\urls.py
from django.contrib import admin
from django.urls import path
from App.views import *
urlpatterns = [
path("index/", index),
path("block/", block),
path("child/", child),
path('admin/', admin.site.urls),
]
App\views.py
import datetime
from django.shortcuts import render
# 模板
def index(request):
data = {
'name': "zhangsan",
'age': 30,
'likes': ['game', 'code', 'movie'],
'address': {
'province': '广东',
'city': '珠海'
},
'stars': [
['辛焱', '大丘丘', '甘雨'],
['虎克', '卡芙卡', '白露'],
['薛之谦', '周杰伦', '陈奕迅']
],
'dt': datetime.datetime.now(),
'code': 'I wander in your yard',
'code2': '''''',
}
return render(request, 'index.html', data)
# 模板继承
# 父模板
def block(request):
return render(request, 'block.html')
# 子模板
def child(request):
return render(request, 'child.html')
新建templates\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django模板</title>
</head>
<body>
<h2>Django模板</h2>
<hr>
{# 单行注释 #}
{% comment %}
多行注释
{% endcomment %}
{# 变量 #}
<p>name:{{ name }}</p>
<p>age:{{ age }}</p>
<p>likes:{{ likes }}</p>
<p>likes.2:{{ likes.2 }}</p>
<p>address:{{ address }}</p>
<p>address.city:{{ address.city }}</p>
<hr>
{# 标签 #}
<h3>if语句</h3>
<h4>单分支</h4>
{# 注意空格 age >= 18 不然报错 #}
{% if age >= 18 %}
<p>{{ name }} 成年啦</p>
{% endif %}
<h4>if双分支</h4>
{% if age >= 18 %}
<p>{{ name }} 成年啦</p>
{% else %}
<p>{{ name }} 未成年</p>
{% endif %}
<h4>if多分支</h4>
{% if age > 60 %}
<p>{{ name }} 老年人</p>
{% elif age >= 18 %}
<p>{{ name }} 壮年</p>
{% else %}
<p>{{ name }} 未成年</p>
{% endif %}
<h4>结合运算符</h4>
{% if age >= 18 and age <= 60 %}
<p>是壮年,风华正茂,小年轻!</p>
{% endif %}
{% if age < 18 or age > 60 %}
<p>未成年或者是老年人!</p>
{% endif %}
{% if 'movie' in likes %}
<p>{{ name }} 喜欢movie!</p>
{% endif %}
<hr>
<h3>for循环</h3>
{% for like in likes %}
<p>{{ like }}</p>
{% endfor %}
<h4>empty</h4>
{# likes2是没有的 #}
{% for like in likes2 %}
<p>{{ like }}</p>
{% empty %}
<p>当likes2为空或不存在时执行empty之后的语句</p>
{% endfor %}
<h4>下标</h4>
{% for like in likes %}
<p>
{# 表示当前是第几次循环,从0数数#}
counter0:{{ forloop.counter0 }}
{# 表示当前是第几次循环,从1数数#}
counter:{{ forloop.counter }}
{# 表示当前是第几次循环,倒着数数,到1停 #}
revcounter:{{ forloop.revcounter }}
{# 表示当前第几次循环,倒着数,到0停#}
revcounter0:{{ forloop.revcounter0 }}
{% if forloop.first %}
<b>--first</b>
{% endif %}
{% if forloop.last %}
<b>--last</b>
{% endif %}
</p>
{% endfor %}
<h4>循环嵌套</h4>
<table border="1" width="500">
{% for star in stars %}
<tr>
{% for s in star %}
<td>
{{ s }}-( {{ forloop.parentloop.counter }} , {{ forloop.counter }} )
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<hr>
<h3>过滤器</h3>
<p>age = {{ age }}</p>
<p>age | add:2 = {{ age | add:2 }}</p>
<p>age | add:-2 = {{ age|add:-2 }}</p>
<p>name = {{ name }}</p>
<p>name|first|upper 名字当中第一个字母大写 = {{ name|first|upper }}</p>
<p>name|last|lower 名字当中最后一个字母小写 = {{ name|last|lower }}</p>
<p>name|title "标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写 = {{ name|title }}</p>
<p>name|truncatechars:4 截断字符串 = {{ name|truncatechars:2 }}</p>
<p>likes = {{ likes }}</p>
<p>拼接 likes = {{ likes|join:"+" }}</p>
<p>likes2 = {{ likes2 }}</p>
<p>likes2|default:'swim' = {{ likes2|default:'swim' }}</p>
<p>dt = {{ dt }}</p>
<p>dt = {{ dt|date:'y-m-d' }}</p>
<p>dt = {{ dt|date:'Y-m-d' }}</p>
<p>code={{ code }}</p>
<p>code|safe={{ code|safe }}</p>
<p>code2={{ code2 }}</p>
{# code2|safe={{ code2|safe }}
#}
打开自动转义转义
{% autoescape on %}
{{ code }}
{% endautoescape %}
关闭自动转义
{% autoescape off %}
{{ code }}
{% endautoescape %}
<br><br><br><br><br>
<br><br><br><br><br>
</body>
</html>
练习继承
templates\block.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父模板</title>
{# css #}
{% block extcss %}
{% endblock %}
</head>
<body>
<h2>父模板</h2>
<hr>
{% block head %}
{% endblock %}
<hr>
{% block content %}
<button>父模板的content中的按钮</button>
{% endblock %}
<hr>
{% block foot %}
{% endblock %}
<hr>
{# js #}
{% block extjs %}
{% endblock %}
</body>
</html>
<ol>
<li>清风</li>
<li>Python</li>
<li>Django</li>
</ol>
templates\child.html
{# 继承父模板 #}
{% extends 'block.html' %}
{% block head %}
<div>
这里是head
</div>
{% endblock %}
{% block content %}
{# 默认情况下,子模板会覆盖父模板的内容 #}
{# 如果想将父模板中的block的内容继承,则需要使用block.super #}
{{ block.super }}
<div>
这里是content
</div>
{% endblock %}
{% block foot %}
<div>
这里是foot
</div>
{% include 'child_include.html' %}
{% endblock %}
Jinja2是之前我们在Flask框架讲过的一个模板引擎,是模仿Django默认模板引擎基础上开发的,比Django模板引擎性能更好,功能更全。
jinja2宣称比django默认模板引擎快10-20倍。Django也支持jinja2
1.安装jinja2模块
pip install jinja2
pip list
查看一下 安装了的python包 或者 pip freeze
按照一定格式输出安装好的包
2.在settings.py所在目录中创建jinja2_env.py文件 (文件名字自己取),并写入以下内容
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': static,
'url': reverse,
})
return env
TEMPLATES = [
# 使用Jinja2模板引擎
{
'BACKEND': 'django.template.backends.jinja2.Jinja2'
,
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
# 这里要添加environment, 并指定到jinja2_env文件中的environment
'environment': 'Day02MyDjangoPro03.jinja2_env.environment',
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
{ # 原来自带的Django模板引擎,保留原来的Django模板
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [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',
],
},
},
]
新建项目Day02MyDjangoPro03
新建jinja2_env.py文件,修改settings.py文件
from django.shortcuts import render
def index(request):
return render(request, 'index.html', {'name': 'zhangsan'})
根目录urls.py
from django.contrib import admin
from django.urls import path
from App.views import *
urlpatterns = [
path('admin/', admin.site.urls),
path('index/',index)
]
templates\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jinja2模板语言</title>
</head>
<body>
<h2>Jinja2模板语言</h2>
{# 变量是跟Django一样的 #}
<p>name = {{ name }}</p>
{% for n in name %}
<b>{{ n }}</b>
{% endfor %}
<hr>
{% for n in name %}
{# Django {{ forloop.counter }}{{ n }}#}
<div>{{ loop.index }}{{ n }}</div>
{% endfor %}
<hr>
{# Django是不能打括号的 #}
{# Jinja2 是可以使用函数调用 #}
{% for i in range(1,4) %}
<div>{{ i }}</div>
{% endfor %}
</body>
</html>