52. django之模板层
1. 模板层语法的传值
1.1 模板层语法
[1] 逻辑相关
{% %}
加载文件系统/ for循环 / if判断
[2] 变量传递
{{ }}
可以将后端的变量名传递到前端
[3] 变量的取值
方法一:{{ }}传递需要传递的变量名
方法二: .属性名取值,只针对对象类型 字典/类的对象/类
当模版系统遇到点("."),它将以这样的顺序查询:
字典查询(Dictionary lookup)
属性或方法查询(Attribute or method lookup)
数字索引查询(Numeric index lookup)
1.2 代码准备
在应用app01的views.py中定义视图类IndexView,定义get与post函数
from django.views import View
# 自定义一个视图类 这个类必须继承django的视图
class IndexView(View):
# 以下函数get与post的名称不能修改,否则发起get/post请求时不能运行对应函数
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
return render(request, 'index.html', locals())
# 当浏览器发起post请求运行这个函数
def post(self, request, *args, **kwargs):
return HttpResponse("from post view")
将视图类IndexView定义为项目的根路由,在总路由里定义,无需在应用路由定义
from django.contrib import admin
from django.urls import path, include
from app01.views import IndexView
urlpatterns = [
path('admin/', admin.site.urls),
path('', IndexView.as_view(), name='index1'),
]
项目下新建static静态文件目录,将bootstrap、jQuery文件放在目录下
settings.py中使用STATICFILES_DIRS加载静态文件系统


应用app01里新建templates目录,目录下新建index.html,加载静态文件系统
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery/jquery.js' %}"></script>
<script src="{% static 'bootstrap/bootstrap.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
</head>
<body>
</body>
</html>
1.3 使用模板层语法传递八大数据类型
应用app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
# 整型
score = 660
# 浮点型
height = 2.06
# 字符串
name = 'her name is avril'
# 列表
num_list = [11, 22, 33, 'aa', 'bb', 'cc']
# 字典
info = {'school': 'mit', 'grade': 1}
# 布尔值
aaa = True
# 集合
num_set = {4, 5, 6, 'd', 'e', 'f'}
# 元组
num_tuple = (7, 8, 9, 'g', 'h', 'i')
return render(request, 'index.html', locals())
# 当浏览器发起post请求运行这个函数
def post(self, request, *args, **kwargs):
return HttpResponse("from post view")
应用app01的index.html中
<body>
<p style="color: purple">传递八大数据类型</p>
<br>
<p>传递整型:</p>
<p>{{ score }}</p>
<p>传递浮点型:</p>
<p>{{ height }}</p>
<p>传递字符串:</p>
<p>{{ name }}</p>
{# 每一个单词的首字母大写 #}
<p>{{ name.title }}</p>
{# 第一个单词的首字母大写 #}
<p>{{ name.capitalize }}</p>
<br>
<p>传递列表:</p>
<p>{{ num_list }}</p>
{# 根据索引取值 #}
<p>{{ num_list.0 }}</p>
<p>传递字典:</p>
<p>{{ info }}</p>
{# 获取字典所有的键 #}
<p>{{ info.keys }}</p>
{# 获取字典所有的值 #}
<p>{{ info.values }}</p>
{# 通过键获取值 #}
<p>{{ info.school }}</p>
<p>传递布尔值:</p>
<p>{{ aaa }}</p>
<p>传递集合:</p>
<p>{{ num_set }}</p>
<p>传递元组:</p>
<p>{{ num_tuple }}</p>
</body>
浏览器访问根目录

1.4 使用模板层语法传递函数
[1] 传递的函数没有参数
应用app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
# 通过get函数传递函数,locals将局部名称空间打包为字典
def get(self, request, *args, **kwargs):
def test01():
print('from test01')
return 'result of test01'
return render(request, 'index.html', locals())
应用app01的index.html中
<body>
<p>传递到前端的函数: {{ test01 }}</p>
</body>
浏览器发起访问时渲染的是函数的返回值

[2] 传递的函数有参数
模板语法不支持被传递的函数有参数
1.5 使用模板层语法传递类与对象
[1] 使用类名传递
应用app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
class Rapper:
def sing(self): # 绑定给对象的方法
return "from sing"
@classmethod # 绑定给类的方法
def rap(cls):
return "from rap"
@staticmethod # 静态方法
def ball():
return "from ball"
# 生成当前类的对象
rap1 = Rapper()
print(f'类Rapper:{Rapper}')
print(f'对象:{rap1}')
return render(request, 'index.html', locals())
应用app01的index.html
<body>
<p>传递类: {{ Rapper }}</p>
</body>
浏览器发起访问打印的内容

后端打印的内容

由图可知,传递类名时,前端实则传递的是类加括号得到的对象
前端渲染自定义类里面的函数,应用app01的index.html
<body>
<p>使用类名传递,实则传递对象: {{ Rapper }}</p>
{# 传递绑定给对象的方法,通过对象调用 #}
<p>传递绑定给对象的方法: {{ Rapper.sing }}</p>
{# 传递绑定给类的方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ Rapper.rap }}</p>
{# 传递静态方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ Rapper.ball }}</p>
</body>

问题:想修改传递类的时候浏览器打印的内容,实则修改对象打印的内容
解决方法:打印对象的内容--->重写元类的_ _str_ _方法 或 _ _call_ _方法
<body>
<p>使用类名传递,实则对象: {{ Rapper }}</p>
</body>
应用app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
class Rapper:
def sing(self):
return "from sing"
@classmethod
def rap(cls):
return "from rap"
@staticmethod
def ball():
return "from ball"
def __str__(self):
return "from __str__"
# 生成当前类的对象
rap1 = Rapper()
print(f'类Rapper:{Rapper}')
print(f'对象:{rap1}')
return render(request, 'index.html', locals())

[2] 使用对象名传递
应用app01的index.html
<body>
<p>使用对象传递: {{ rap1 }}</p>
{# 传递绑定给对象的方法,通过对象调用 #}
<p>传递绑定给对象的方法: {{ rap1.sing }}</p>
{# 传递绑定给类的方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ rap1.rap }}</p>
{# 传递静态方法,通过对象调用 #}
<p>传递静态方法: {{ rap1.ball }}</p>
</body>

使用类名传递与使用对象传递,前端渲染的都是对象
2. 过滤器
2.1 前言
应用app01的views.py中,将a标签以字符串形式传递给前端
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
h5_str = '<a href="">点击加金币</a>'
return render(request, 'index.html', locals())
应用app01的index.html
<body>
{{ h5_str }}
</body>
浏览器渲染的结果是字符串而不是链接

2.2 过滤器作用
在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
2.3 语法
{{ name|filter_name:参数 }}
使用管道符" | "来应用过滤器
name:后端的变量名
filter_name:过滤器名称
参数:过滤器需要的参数(可选)
2.4 使用方法
[1] 计算长度(length)
语法:
{{ name|length }}
计算变量的长度,作用于字符串和列表。
代码:
应用app01的index.html
<body>
{{ h5_str|length }}
</body>
计算后端h5_str变量的长度

[2] 默认值(default)
语法:
{{ name|default:"123"}}
如果name的值为空或者为布尔False的话就显示123
变量name有值则显示对应的值,如果值为空或者为False(布尔值非字符串"False"),则显示default后面定义的默认值。
代码:
应用app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
a = True # 布尔值不为False显示实际的值
b = False
c = 'False' # 字符串'False'不是布尔值
d = ''
return render(request, 'index.html', locals())
应用app01的index.html
<body>
{{ a|default:123 }}
<br>
{{ b|default:'123' }}
<br>
{{ c|default:'123' }}
<br>
{{ d|default:'123' }}
</body>

[3] 文件大小(filesizeformat)
语法:
{{ name|filesizeformat }}
将值格式化为一个 “人们可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。
例如:name的值是 123456789,输出将会是 117.7 MB。
[4] 日期格式化(date)
语法:
{{ name|date:"Y-m-d H:i:s"}}
注意前端时间字符串格式与python时间字符串格式的区别
前端日期格式化参数:
| 格式化字符 | 描述 | 示例输出 |
|---|---|---|
| a | 'a.m.'或'p.m.'(请注意,这与PHP的输出略有不同,因为这包括符合Associated Press风格的期间) |
'a.m.' |
| A | 'AM'或'PM'。 |
'AM' |
| b | 月,文字,3个字母,小写。 | 'jan' |
| B | 未实现。 | |
| c | ISO 8601格式。 (注意:与其他格式化程序不同,例如“Z”,“O”或“r”,如果值为naive datetime,则“c”格式化程序不会添加时区偏移量(请参阅datetime.tzinfo) 。 |
2008-01-02T10:30:00.000123+02:00或2008-01-02T10:30:00.000123如果datetime是天真的 |
| d | 月的日子,带前导零的2位数字。 | '01'到'31' |
| D | 一周中的文字,3个字母。 | “星期五” |
| e | 时区名称 可能是任何格式,或者可能返回一个空字符串,具体取决于datetime。 | ''、'GMT'、'-500'、'US/Eastern'等 |
| E | 月份,特定地区的替代表示通常用于长日期表示。 | 'listopada'(对于波兰语区域,而不是'Listopad') |
| f | 时间,在12小时的小时和分钟内,如果它们为零,则分钟停留。 专有扩展。 | '1','1:30' |
| F | 月,文,长。 | '一月' |
| g | 小时,12小时格式,无前导零。 | '1'到'12' |
| G | 小时,24小时格式,无前导零。 | '0'到'23' |
| h | 小时,12小时格式。 | '01'到'12' |
| H | 小时,24小时格式。 | '00'到'23' |
| i | 分钟。 | '00'到'59' |
| I | 夏令时间,无论是否生效。 | '1'或'0' |
| j | 没有前导零的月份的日子。 | '1'到'31' |
| l | 星期几,文字长。 | '星期五' |
| L | 布尔值是否是一个闰年。 | True或False |
| m | 月,2位数字带前导零。 | '01'到'12' |
| M | 月,文字,3个字母。 | “扬” |
| n | 月无前导零。 | '1'到'12' |
| N | 美联社风格的月份缩写。 专有扩展。 | 'Jan.','Feb.','March','May' |
| o | ISO-8601周编号,对应于使用闰年的ISO-8601周数(W)。 对于更常见的年份格式,请参见Y。 | '1999年' |
| O | 与格林威治时间的差异在几小时内。 | '+0200' |
| P | 时间为12小时,分钟和'a.m。'/'p.m。',如果为零,分钟停留,特殊情况下的字符串“午夜”和“中午”。 专有扩展。 | '1 am','1:30 pm' / t3>,'midnight','noon','12:30 pm' / T10> |
| r | RFC 5322格式化日期。 | 'Thu, 21 Dec 2000 16:01:07 +0200' |
| s | 秒,带前导零的2位数字。 | '00'到'59' |
| S | 一个月的英文序数后缀,2个字符。 | 'st','nd','rd'或'th' |
| t | 给定月份的天数。 | 28 to 31 |
| T | 本机的时区。 | 'EST','MDT' |
| u | 微秒。 | 000000 to 999999 |
| U | 自Unix Epoch以来的二分之一(1970年1月1日00:00:00 UTC)。 | |
| w | 星期几,数字无前导零。 | '0'(星期日)至'6'(星期六) |
| W | ISO-8601周数,周数从星期一开始。 | 1,53 |
| y | 年份,2位数字。 | '99' |
| Y | 年,4位数。 | '1999年' |
| z | 一年中的日子 | 0到365 |
| Z | 时区偏移量,单位为秒。 UTC以西时区的偏移量总是为负数,对于UTC以东时,它们总是为正。 | -43200到43200 |
代码:
(1)日期数据不加以格式化传递到前端
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
now_time = datetime.datetime.now()
print(now_time) # 2026-03-03 23:00:52.938038
return render(request, 'index.html', locals())
app01的index.html
<body>
{{ now_time }}
</body>

(2)日期数据格式化传递到前端
app01的index.html
<body>
{{ now_time }}
<br>
{{ now_time|date:"Y-m-d H:i:s" }}
</body>

[5] 切片
语法:
{{ value|slice:'起始:结束:步长' }}
与python切片取值一样,顾头不顾尾
代码:
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
info = '123abc456'
return render(request, 'index.html', locals())
app01的index.html
取索引0到5的值,步长为2
<body>
{{ info|slice:'0:6:2' }}
</body>

[6] 切取摘要(truncatechars)
语法:
{{ name|truncatechars:指定字符数}}
按指定字符数对变量值进行获取,如果变量值的字符数多于指定字符数,多于的部分以省略号("...")展示
代码:
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
info = 'Her name is avril'
return render(request, 'index.html', locals())
app01的index.html
<body>
{{ info|truncatechars:6 }}
</body>

[7] 移除指定字符(cut)
语法:
{{ value|cut:'指定字符' }}
移除value中所有个数的指定字符
代码:
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
info = 'Her name is avril'
info2 = 'Canada Toronto'
return render(request, 'index.html', locals())
app01的index.html
<body>
{# 移除所有空格 #}
{{ info|cut:' ' }}
<br>
{# 移除所有字母n #}
{{ info2|cut:'n'}}
</body>

[8] 拼接字符(join)
语法:
{{ name|join:'指定字符' }}
将可迭代类型用指定字符进行拼接
代码:
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
info_list = ['her', 'name', 'is', 'avril']
return render(request, 'index.html', locals())
app01的index.html
<body>
{# 用空格进行拼接 #}
{{ info_list|join:' ' }}
<br>
{# 用~进行拼接 #}
{{ info_list|join:'~'}}
</body>

[9] 加法(add)
语法:
{{ name|add:'指定数字' }}
给变量值加上指定数字
后端与前端的数字既可以是整型,也可以是字符串形式的整型
代码:
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
a = 15
return render(request, 'index.html', locals())
app01的index.html
<body>
{# 加上整数 #}
{{ a|add:1 }}
<br>
{# 加上字符串 #}
{{ a|add:'4' }}
</body>

[10] 重要:转义(mark_safe和safe)
(1) 概念
django的模板中,后端传递HTML标签给前端,浏览器访问时不会对HTML标签进行转义;而有时需要进行转义,转义与取消转义的方法既可以作用于后端,也可以作用于前端。
(2) 前端转义(safe)
根据2.1可知,后端将HTML标签传递给前端,浏览器展示的标签的字符串,而非转义后的链接。
前端使用过滤器safe进行转义
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
h5_str = '<a href="">点击加金币</a>'
return render(request, 'index.html', locals())
app01的index.html
<body>
{{ h5_str|safe }}
</body>

(3) 后端转义(mark_safe)
app01的views.py
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
h5_str = mark_safe('<a href="">点击加装备</a>')
return render(request, 'index.html', locals())
app01的index.html
<body>
{{ h5_str }}
</body>

3. 标签
3.1 模板层语法加载逻辑相关---for循环
[1] 语法
(1) for循环语法
{% for user in user_list %}
{{ user.name }}
{% endfor %}
(2) for ... empty
for循环中可迭代类型的值为空的时候,就会展示empty里的内容
{% for user in user_list %}
{{ user.name }}
{% empty %}
空空如也
{% endfor %}
[2] for循环的一些参数
| Variable | Description |
|---|---|
forloop.counter |
当前循环的索引值(从1开始) |
forloop.counter0 |
当前循环的索引值(从0开始) |
forloop.revcounter |
当前循环的倒序索引值(从高到低,低从1开始) |
forloop.revcounter0 |
当前循环的倒序索引值(从高到低,低从0开始) |
forloop.first |
当前循环是不是第一次循环(布尔值) |
forloop.last |
当前循环是不是最后一次循环(布尔值) |
forloop.parentloop |
本层循环的外层循环 |
3.2 模板层语法加载逻辑相关---if判断
[1] if ~ elif ~ else
{% if 条件1 %}
{% elif 条件2 %}
{% else %}
{% endif %}
[2] 只有if和else
{% if 条件 %}
{% else %}
{% endif %}
[3] for循环与if判断的代码
app01的views.py中
class IndexView(View):
# 当浏览器发起get请求运行这个函数
def get(self, request, *args, **kwargs):
info = {}
for i in range(6):
info[f'avril_{i}'] = {
'name': f'avril_{i}',
'num': i,
'hobby': 'sing' if i % 2 == 0 else 'swim'
}
return render(request, 'index.html', locals())
app01的index.html中
<body>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>姓名</th>
<th>数字</th>
<th>爱好</th>
</tr>
</thead>
<tbody>
{% for v in info.values %}
{% if forloop.first %} {% comment %}第一个循环{% endcomment %}
<tr class="active">
<th scope="row">{{ forloop.revcounter0 }}</th>
{% comment %}索引从0开始,倒序{% endcomment %}
<td>{{ v.name }}</td>
<td>{{ v.num }}</td>
<td>{{ v.hobby }}</td>
</tr>
{% elif forloop.last %} {% comment %}最后一个循环{% endcomment %}
<tr class="success">
<th scope="row">{{ forloop.revcounter0 }}</th>
{% comment %}索引从0开始,倒序{% endcomment %}
<td>{{ v.name }}</td>
<td>{{ v.num }}</td>
<td>{{ v.hobby }}</td>
</tr>
{% else %}
<tr class="info">
<th scope="row">{{ forloop.revcounter0 }}</th>
<td>{{ v.name }}</td>
<td>{{ v.num }}</td>
<td>{{ v.hobby }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</body>

4. 自定义过滤器/自定义简单标签/自定义包含标签
4.1 前言
准备工作:
在应用app01下新建一个templatetags目录(目录名称不能修改)
该文件夹下新建一个任意名称的py文件
在该文件内调用Library(调用语句保持如下,不要修改)

随便点开一个过滤器就能看到以上两行代码
以上创建了一个django图书馆对象,需要向图书馆对象增加自定义的数据
4.2 自定义过滤器
以上py文件中自定义过滤器
自定义过滤器的函数只能有两个参数,即前端使用过滤器冒号之后只能有一个参数
from django import template
register = template.Library()
# 自定义过滤器,代码参照实际过滤器的函数
@register.filter(is_safe=True)
def self_filter(a, b):
return a + b
app01的views.py中定义视图函数
def index(request):
a = 1
return render(request, 'index.html', locals())
将index函数的路由设置为根目录
from app01.views import index
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='index1'),
]
app01的templates目录下新建index.html文件,使用自定义的过滤器
{% load NewTag %} {% comment %}加载过滤器{% endcomment %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery/jquery.js' %}"></script>
<script src="{% static 'bootstrap/bootstrap.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
</head>
<body>
{{ a|self_filter:666 }}
</body>
</html>
浏览器发起访问即使用自定义过滤器

4.3 自定义简单标签
simple_tag直接返回字符串 / HTML / 数值
前端的for循环中点击for查看标签的源码
在templatetags的py文件中自定义简单标签,自定义标签可以接收任意个参数
from django import template
register = template.Library()
# 自定义标签
@register.simple_tag(name='NewTag') # 一定要用关键字参数,不能直接写变量值
def func1(a, b, c, d):
return a + b + c + d
视图函数与路由如4.2
app01的templates目录下使用自定义标签
{% load SelfTag %} {% comment %}加载文件{% endcomment %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery/jquery.js' %}"></script>
<script src="{% static 'bootstrap/bootstrap.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
</head>
<body>
{% NewTag 1 2 3 4 %}
</body>
</html>


4.4 自定义包含标签
[1] 概念
inclusion_tag渲染一个独立的模板片段(HTML页面的局部,不能是完整的代码),返回 HTML
先定义一个函数(即包含标签)
在页面局部调用该函数,函数可以传值给页面局部
再将页面局部返回给前端
[2] 代码

视图函数与路由如4.1,将index函数设置为根目录函数,返回index.html页面
index.html中调用自定义包含标签的函数
{% load SelfTag %} {% comment %}加载文件{% endcomment %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery/jquery.js' %}"></script>
<script src="{% static 'bootstrap/bootstrap.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
</head>
<body>
{% func2 3 %} {% comment %}相当于在页面上封装了能产生html代码的方法{% endcomment %}
{% func2 5 %}
</body>
</html>
在templatetags的py文件中自定义包含标签
from django import template
register = template.Library()
# 自定义包含标签
@register.inclusion_tag('visit.html')
def func2(n):
l1 = []
for i in range(1, n+1):
l1.append(f'序号{i}')
return locals()
以上自定义包含标签函数调用了局部页面,会将列表l1的值传给visit.html
<div>
{% for a in l1 %}
<p>{{ a }}</p>
{% endfor %}
</div>
浏览器发起访问时,index.html使用到了局部页面visit.html

[3] 总结
当html页面的某一个部分需要传参数才能动态的渲染出来,并且在多个页面上都需要使用到的局部,那么可以将该局部页面做成 inclusion_tag 形式
访问步骤:
前端调用自定义包含标签函数---自定义包含标签函数调用局部页面,传值给局部页面---前端使用局部页面
5. 模板继承
5.1 准备工作
app01的views.py中定义home、login、reg视图函数
def home(request):
return render(request, 'home.html')
def login(request):
return render(request, 'login.html')
def reg(request):
return render(request, 'reg.html')
app01的templates目录新建home.html、login.html、reg.html
将视图函数的路由添加到总路由
from app01.views import index, home, login, reg
urlpatterns = [
path('admin/', admin.site.urls),
path('', index),
path('home/', home),
path('login/', login),
path('reg/', reg),
]
5.2 代码
给home.html添加代码:
将[导航条]放在body里,https://v3.bootcss.com/components/#navbar
[导航条]的<nav class="navbar navbar-default">的default改为inverse
[导航条]之后放页面主体,页面主体设置一个container-fluid容器
col-md-2里面放[链接]---col-md-10里面放[带标题的面板,有title的部分]
[带标题的面板]panel-default改为panel-primary
[带标题的面板]panel-body放[巨幕],[巨幕]之后放[缩略图](默认样式),[缩略图]里添加图片
给col-md-2的list-group的a标签添加路径
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
</head>
<body>
{% comment %}导航条{% endcomment %}
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% comment %}页面主体{% endcomment %}
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
<div class="list-group">
<a href="/home/" class="list-group-item active">
首页
</a>
<a href="/reg/" class="list-group-item">注册</a>
<a href="/login/" class="list-group-item">登录</a>
<a href="#" class="list-group-item">后台</a>
<a href="#" class="list-group-item">其它</a>
</div>
</div>
<div class="col-md-10">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">专业网站</h3>
</div>
<div class="panel-body">
<div class="jumbotron">
<h1>rap学习网站</h1>
<p>更多rap知识...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">点击开始学习</a></p>
</div>
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="{% static 'pics/1.jpeg' %}" alt="...">
</a>
</div>
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="{% static 'pics/2.jpeg' %}" alt="...">
</a>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="{% static 'pics/3.jpg' %}" alt="...">
</a>
</div>
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="{% static 'pics/4.jpeg' %}" alt="...">
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

注册、登录的a标签有实际指向的路由,此时login.html、reg.html内容为空,点击注册、登录时页面为空
需求:点击登录、注册时不再为空,效果在home页面基础上只有col-md-10里面板网站的内容发生变化,登录、注册栏和导航条都不发生变化
方法:使用模板继承
将login.html与reg.html新建文件时带有的内容清空,分别使用extends方法即可
{% extends 'home.html' %}

再次点击注册、登录时页面内容不再为空,而是与home页面一致
1.在模板html代码上打好标签,用以声明被继承后哪些部分可以修改
{% block content %}
{% endblock %} 包含的内容可以被修改
将巨幕的内容放在block里面
{% block content %} <div class="jumbotron"> <h1>rap学习网站</h1> <p>更多rap知识...</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">点击开始学习</a></p> </div> {% endblock %}
2.继承extends与修改
reg.html修改block content内容
{% extends 'home.html' %}
{% block content %}
<p>注册页面</p>
{% endblock %}
login.html修改block content内容
{% extends 'home.html' %}
{% block content %}
<p>登录页面</p>
{% endblock %}
再次点击注册、登录时,页面不再为空,内容复制了home页面,但是巨幕部分被修改


5.3 补充
模板html代码建议设置三个区域:css区域、内容区域、js区域
css区域放在head标签的末尾,用于继承后扩展css
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap/bootstrap.css' %}">
{% block css %}
{% endblock %}
</head>
js区域放在body标签的末尾,用于继承后扩展js
<body>
...
...
{% block js %}
{% endblock %}
</body>
继承页面使用被继承页面的内容 {{ block.super }}
在注册页面中两次使用被继承的区域巨幕的内容
{% extends 'home.html' %}
{% block content %}
<p>注册页面</p>
{{ block.super }}
{{ block.super }}
{% endblock %}


浙公网安备 33010602011771号