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加载静态文件系统

image

 image

应用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>

浏览器访问根目录

image

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>

浏览器发起访问时渲染的是函数的返回值

image

[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>

浏览器发起访问打印的内容

image

后端打印的内容

image

由图可知,传递类名时,前端实则传递的是类加括号得到的对象

前端渲染自定义类里面的函数,应用app01的index.html

<body>
<p>使用类名传递,实则传递对象: {{ Rapper }}</p>
{# 传递绑定给对象的方法,通过对象调用 #}
<p>传递绑定给对象的方法: {{ Rapper.sing }}</p>
{# 传递绑定给类的方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ Rapper.rap }}</p>
{# 传递静态方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ Rapper.ball }}</p>
</body>

image

问题:想修改传递类的时候浏览器打印的内容,实则修改对象打印的内容

解决方法:打印对象的内容--->重写元类的_ _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())

image

[2] 使用对象名传递

应用app01的index.html

<body>
<p>使用对象传递: {{ rap1 }}</p>

{# 传递绑定给对象的方法,通过对象调用 #}
<p>传递绑定给对象的方法: {{ rap1.sing }}</p>
{# 传递绑定给类的方法,通过对象调用 #}
<p>传递绑定给类的方法: {{ rap1.rap }}</p>
{# 传递静态方法,通过对象调用 #}
<p>传递静态方法: {{ rap1.ball }}</p>
</body>

image

使用类名传递与使用对象传递,前端渲染的都是对象

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>

浏览器渲染的结果是字符串而不是链接

image

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变量的长度

image

[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>

image

[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:002008-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 布尔值是否是一个闰年。 TrueFalse
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周数,周数从星期一开始。 153
y 年份,2位数字。 '99'
Y 年,4位数。 '1999年'
z 一年中的日子 0365
Z 时区偏移量,单位为秒。 UTC以西时区的偏移量总是为负数,对于UTC以东时,它们总是为正。 -4320043200

代码:

(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>

image

(2)日期数据格式化传递到前端

 app01的index.html

<body>
    {{ now_time }}
    <br>
    {{ now_time|date:"Y-m-d H:i:s" }}
</body>

image

[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>

image

[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>

image

[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>

image

[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>

image

[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>

image

[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>

image

(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>

image

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循环的一些参数

VariableDescription
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>

image

4. 自定义过滤器/自定义简单标签/自定义包含标签

4.1 前言

准备工作:

在应用app01下新建一个templatetags目录(目录名称不能修改)

该文件夹下新建一个任意名称的py文件

在该文件内调用Library(调用语句保持如下,不要修改)

image

随便点开一个过滤器就能看到以上两行代码

以上创建了一个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>

浏览器发起访问即使用自定义过滤器

image

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>

image

image

4.4 自定义包含标签

[1] 概念

inclusion_tag渲染一个独立的模板片段(HTML页面的局部,不能是完整的代码),返回 HTML

 

先定义一个函数(即包含标签)

在页面局部调用该函数,函数可以传值给页面局部

再将页面局部返回给前端

[2] 代码

image

视图函数与路由如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

image

[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>

image

注册、登录的a标签有实际指向的路由,此时login.html、reg.html内容为空,点击注册、登录时页面为空

需求:点击登录、注册时不再为空,效果在home页面基础上只有col-md-10里面板网站的内容发生变化,登录、注册栏和导航条都不发生变化

方法:使用模板继承

将login.html与reg.html新建文件时带有的内容清空,分别使用extends方法即可

{% extends 'home.html' %}

image

再次点击注册、登录时页面内容不再为空,而是与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页面,但是巨幕部分被修改

image

image

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 %}

image

 

posted @ 2026-03-16 18:26  pythondjango  阅读(3)  评论(0)    收藏  举报