4.Django 模板语法

     阅读:25

1. FBV与CBV

FBV(基于函数的视图)
CBV(基于类的视图)
Python 是一个门面向对象的编程语言。如果我们只用函数来编写视图函数,
那么就会造成很多面向对象的优点无法利用起来,比如说封装、继承、多态等

1.1 FBV

FBV 基于函数的视图
在views.py视图中中定义函数来处理用户请求,
函数中再定义如果是GET请求怎么处理,POST请求怎么处理...
0. 新建一个项目,解决template文件夹路径错误,注释中间件.
1. 项目路由层
2. app01视图函数
# 项目的路由层
from django.conf.urls import url
from django.contrib import admin
# 0. 导入 数图函数
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 1. FBV 方式
    url(r'^register/', views.register),
]
# app01 的视图层
# 0. 导入Python 三板斧
from django.shortcuts import render, HttpResponse, redirect

# 1.定义函数
def register(request):
    # 写逻辑
    return HttpResponse('index页面')

1.2 CBV

CBV 基于类的视图
体现了Python面向对象这一语言特性。CBV 是通过类的方式来编写视图函数.
这相比较于函数,更能利用面向对象中多态的特性,因此更容易将项目中比较通用的功能抽象出来。
* urls.py文件中CBV的书写方式  类名.as_view() 方式映射,
定义的类需要继承 View ,
定义的方法按照固定样式,View类中支持以下方法:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
CBV的特点:能根据不同的请求方式匹配对应的方法执行。
0. 项目路由层
1. app01视图函数
2. template 目录下创建 login.html
    # 项目的路由层
    # 2. CBV 方式
    url(r'^login/', views.Login.as_view())
# 2. 导入 View 类
from django.views import View


# 3.定义类
class Login(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        return HttpResponse('Login页面 POST 请求')
<!--项目目录下建立login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登入页面</title>
</head>
<body>
    <div>
        <form action="" method="post">
            <input type="submit">
        </form>
    </div>
</body>
</html>

image-20220306021339413

3. 在浏览器中输入: 127.0.0.1:8000/login
4. 点提交

image-20220306021925394

1.3 CBV源码解析

1.启动程序时

image-20220306151703298

函数名,方法名加括号执行优先级最高。
在启动 Django 时就会执行 views.mylogin.as_view()

Login是类名,类使用.as_view()

查看源代码可以得知 结果就是 views.view

url('^login/', views.Login.as_view()) 
变形为 url('^login/', views.view), 

CBV和FBV在路由上本质是一样的,都是路由对应函数内置地址。 

在输入127.0.0.1:8000/login时触发 views.view
2.请求来的时候
getattr 反射:通过字符串来操作对象的属性或者方法
getattr(自己写的类对象,'小写的请求方式get/post',当找不这个小写的请求时才使用第三个参数)

不要修改源码,出现bug难查找。
在查看源码的时候一定要时刻提醒自己面对对象属性方法的查找顺序。
在查看源码时看到self.东西,一定要问自己当前这个self是谁
1. 先从自己的对象中找
2. 再去产生对象的类中查找
3. 父类中查找
# 源码
class View(object):
	# http的方法名字
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
	
    # View加括号的时候执行
    def __init__(self, **kwargs):
		# 遍历 kwargs 关键字参数, 通过setattr(对象, 属性, 值)设置默认值
        for key, value in six.iteritems(kwargs):
            setattr(self, key, value)
	
    # 静态方法
    @classonlymethod
    def as_view(cls, **initkwargs):
		# 关键字参数是否符合要求, 不符合就 raise 抛出错误.
        for key in initkwargs:
            #  关键字参数的变量名必须是 http的方法列表中的其中一个
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            # hasattr(cls-->类名, 关键字参数的变量名) 函数用于判断对象是否包含对应的属性。    
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            # self = Login(**initkwargs)
            self = cls(**initkwargs)
            # 当对象中有get属性 and 没有 head 属性的时候,   get 赋值给 head
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            # 对象.request 接收  request
            self.request = request
            # 对象.args 接收位置参数
            self.args = args
            # 对象.kwargs 接收关键字参数
            self.kwargs = kwargs
            # 返回 对象.dispatch()函数
            return self.dispatch(request, *args, **kwargs)
        """
        其他的不看了
        """
        return view

    def dispatch(self, request, *args, **kwargs):
        """
        request.method.lower()  获取请求方式 转小写
        判断 请求是否在 http方法列表中
        如果 存在 则取 去自己写的类总找对应请求名字的方法 赋值 给 handler, 
        				自己没有写这个请求的方法就抛出异常
        如果不存在,就将抛出异常的代码 赋值 给 handler
        
      	执行handler  handler要么是自己写的请求方法 要么是请求不存在http方法列表中报错
        """
        if request.method.lower() in self.http_method_names:
            # 方法 =      获取    对象中   请求方法                如果没有就抛出错误
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
    		# 不存在抛出错误
            handler = self.http_method_not_allowed
        
        return handler(request, *args, **kwargs)
    """
    其他的不看了
    """

2. 模板层

2.1 模板语法

模板语法的书写方法:
{{ 变量名 }}  变量相关
{%  %}       逻辑相关 for循环等
基本的数据类型都可以传递给前端。

模板语法内部会自动判断当前的变量(函数名, 类名)是否可以加括号调用,
如果可以就会自定加括号执行。

传递函数名会自动加括号进行调用,传递的是返回值.
传递类名的时候也会自动加括号实例化,传递的是对象.

* 模板语法不支持函数传递额外的参数,如果函数带参数则不会执行这条模板语法语句。
Django模板语法的取值格式:
1. 句点符 .键取值
2. 可以点索引
3. 两者混合使用

2.2 测试环境

1. 路由层
	# 项目的urls.py
    # 4.索引
    url('^index/', views.index)
2. 视图层
# app01的views.py
# 4.index 模板语法测试
def index(request):
    # 返回index.html 页面
    return render(request, 'index.html')
3.前端页面
templates目录下创建index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法测试</title>
</head>
<body>
    <h1>模板语法测试</h1>
    <!--下面写测试的模板语法-->
</body>
</html>

image-20220306173202577

2.3 基本数据类型传递

模板语法可以传入后端Python数据类型
整型, 浮点型 字符串, 列表, 元组, 字典, 集合, 布尔值
# app01 views.py
# 4.index 模板语法测试
def index(request):
    # 返回index.html 页面
    # 基本数据类
    int_ = 1
    float_ = 1.1
    str_ = 'hello'
    list_ = [1, 2]
    tuple_ = (1, 2)
    dict_ = {'k1': 'v1'}
    set_ = {1, 2}
    bool_ = True
    print(locals())
    return render(request, 'index.html', locals())
<!-- templates 在 index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法测试</title>
</head>
<body>
    <h1>模板语法测试</h1>
    <!--下面写测试的模板语法-->
    {{ int_ }}
    {{ float_ }}
    {{ str_ }}
    {{ list_ }}
    {{ tuple_ }}
    {{ dict_ }}
    {{ set_ }}
    {{ bool_ }}
</body>
</html>

image-20220306175229383

.键取值
索引取值
值可以使用方法.
# app01 views.py
# 4.index 模板语法测试
def index(request):
    # 返回index.html 页面
    # 索引 .键 取值
    str_ = 'hello'
    list_ = [1, 2]
    tuple_ = (1, 2)
    dict_ = {'k1': 'v1', 'k2': 'v2'}
    dir1 = {'name': ['you', {'小名': ['二狗子', '狗剩']}]}

    print(locals())
    return render(request, 'index.html', locals())
<!-- templates 在 index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法测试</title>
</head>
<body>
    <h1>模板语法测试</h1>
    <!--下面写测试的模板语法-->

    <p> {{ str_.0 }} {{ str_.1 }} </p>
    <p> {{ list_.0 }}  </p>
    <p> {{ tuple_.0 }} </p>
    <p> {{ dict_.keys }}  {{ dict_.values }} {{ dict_.k1 }}</p>
    <p> {{ dir1.name.0 }} </p>
    <p> {{ dir1.name.1.小名 }}</p>
</body>
</html>

image-20220306180351798

2.4 传递函数结果

# app01 views.py
# 4.index 模板语法测试
def index(request):
    def func1():
        return 'func1 的返回值'

    # 返回index.html 页面
    print(locals())
    return render(request, 'index.html', locals())
<!-- templates 在 index.html  中-->
    <p> {{ func1 }} </p>

image-20220306180843158

函数携带参数的话,模块语法没有办法提供参数给函数,就直接不执行了.

image-20220306204824278

# 4.index 模板语法测试d
def index(request):
    class Myclass1(object):
        def get_self(self):
            print(0)
            return self

        @staticmethod  # 静态方法,不传递self参数, 函数中不需要self
        def func():
            print(1)
            return '静态方法'

        @classmethod  # 类使用属性方法,将自己做第一个参数进行传递
        def get_class(cls):
            print(2)
            return cls

    print(locals())
    return render(request, 'index.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法测试</title>
</head>
<body>
    <h1>模板语法测试</h1>
    <!--下面写测试的模板语法-->
    <p> {{ Myclass1.get_self }} </p>
    <p> {{ Myclass1.func }} </p>
    <p> {{ Myclass1.get_class }} </p>
</body>
</html>

image-20220306210808518

只有是函数名称空间中名称都会被 locals()查出来,传到前端页面中.

image-20220306211355157

3. 过滤器

过滤器是模板语法的内置方法。
Django内置有60多个过滤器。

过滤器的基本语法:
{{ 数据|过滤器:参数}}
自定义的过滤器的参数最多就2

3.1 常见过滤器

1. length         统计长度 (内部源码len())
2. default        默认值 第一个数据布尔值为True就展示第一个数据的值,否则就展示冒号后面的值。
3. filesizeformat 文件大小,将字节进行对应的单位换算。
4. date           日期格式。
5. slice          切片操作, 支持步长。
6. truncatechars  切取字符,三个点就占三个字符,设置大于3,不然就看到三个点。
7. truncatewords  按空格切取单词,不不包含三个点。
8. cut            移除特定的字符
9. join           拼接操作
10. add           加法
11. safe          转义
1. 统计长度
length  统计长度 (内部源码len())
	str_ = '1234'

    <p>长度统计: {{ str_|length }} </p>   

    # 统计长度:3

image-20220306213208519

2.默认值
default 默认值 |前面的数据 布尔值为True 就展示第一个数据的值,否则就展示default冒号后面的值。
    bool_0 = True
    bool_1 = False

    <p> {{ bool_0|default:'前面的值为True 我就不打印' }} </p>
    <p> {{ bool_1|default:'前面的值为False 我不打印' }} </p>

image-20220306212856735

3.文件大小
filesizeformat 文件大小,将字节进行对应的单位换算。
    file_size1 = 1000000
    file_size2 = 56565265

    <p>{{ file_size1|filesizeformat }}</p>
    <p>{{ file_size2|filesizeformat }}</p>

    # 976.6 KB
    # 53.9 MB

image-20220306213301853

4.日期格式
格式设置 date:'Y-m-d H:i:s'  配合datetime使用
    import datetime
    now_time = datetime.datetime.now()
    
    <p>现在时间:{{ current_time }}</p>
    <p>格式设置:{{ current_time|date:'Y-m-d H:i:s' }}</p>

    # 现在时间:Aug. 15, 2021, 8:08 p.m.
    # 格式设置:2021-08-15 20:08:23

image-20220306213922745

5.切片操作
slice切片操作, 支持步长。
    list_ = ['qz', 'qq', 'cc', 'dd']

    <p>切片操作:{{ list_|slice:'0:3:2' }}</p>

    # 切片操作:['qz', 'cc']

image-20220306214516820

6.切取字符
truncatechars 切取字符,默认有三个点占三个字符,设置大于3,不然就看到三个点。
    info = "abcdefghijklmnopqrst"

    <p>窃取操作:{{ info|truncatechars:3 }}</p>
    <p>窃取操作:{{ info|truncatechars:6 }}</p>

    # 切取操作:...
    # 切取操作:abc...

image-20220306215144712

7.切取单词
truncatewords:x 按空格取分单词,切x个.   末尾有三个点。
    msg = 'hao hao xue xi ha ha'

    <p>切取单词:{{ egl|truncatewords:3 }}</p>

    # 切取单词:hao hao xue ...

image-20220306214800623

8.移除特定的字符
cut 移除特定的字符
    msg = 'hao hao xue xi ha ha'

    <p>移除特定字符:{{ egl|cut:' ' }}</p>
    <p>移除特定字符:{{ egl|cut:'cao' }}</p>

    # 移除特定字符:nihaoawocaolei
    # 移除特定字符:ni hao a wo lei

image-20220306215448331

9.拼接操作
join 拼接操作 每个元素添加字符
(* 只能是字符串做拼接)
    msg = 'hao hao xue xi ha ha'
    list_ = ['qz', 'qq', 'cc', 'dd']


    <p>拼接操作:{{ msg|join:'---' }}</p>
    <p>拼接操作:{{ list_|join:'---' }}</p>

    # 拼接操作:h---a---o--- ---h---a---o--- ---x---u---e--- ---x---i--- ---h---a--- ---h---a
    # 拼接操作:qz---qq---cc---dd

image-20220306215823914

10.加法
add 数字相加, 字符串拼接,否则 ' '空字符串。
    str1 = '100'
    str2 = 'aaa'

    <p>加法运算:{{ str1|add:100 }}</p>
    <p>加法拼接:{{ str2|add:s3}}</p>

# 加法运算:200
# 加法拼接:aaa100

image-20220306220226778

11.前端转义
让前端执行转义。
    h1 = '<h1>xxx</h1>'

    <p>前端转义:{{ h1|safe }}</p>

    # 前端转义:xxx   (1号标题)

image-20220306220348037

后端转义:
以后在写全栈项目的时候,前端页面不一定要在前端页面书写,
也可以在后端写好,然后传递给前端页面,需要使用 mark_safe模块.

from django.utils.safestring import  mark_safe('html代码')
res = mark_safe('html代码')
    from django.utils.safestring import mark_safe
    res = mark_safe('<h1>xxx</h1>')

    <p>转义:{{ res }}</p>

    # 后端转义:xxx   (1号标题)

image-20220306220548326

4. 标签

{% 开始 %} 

{% 结束 %}

4.1 for循环

{% for 变量 in  %} 
	{{循环体}}
{% endfor %}
list_  = ['aa', 'bb', 'cc', 'dd', 'dd']
	<!--for i in lll-->
    {% for i in list_  %}   
        <!--一个个元素-->
        <p> {{ i }} </p>         
    {% endfor %}

image-20220306223509217

4.2 forloop 参数

forloop 一个排序信息的字典
forloop.字典中的键取到值.
    # forloop 参数
    {% for foo in list_  %}
        <p> {{ forloop }} </p>

    {% endfor %}

image-20220306224113288

    {% for foo in list_ %}
        <p>
            {{ forloop.counter0 }} {{ forloop.counter }}
            {{ forloop.revcounter0 }} {{ forloop.revcounter }}
            {{ forloop.first }} {{ forloop.last }}
        </p>

    {% endfor %}

image-20220306231708504

4.3 if判断

{% if判断语句 %}
	if表达式为真执行的代码块
{% elif num == 10 %}
	if表达式为真执行的代码块
{% else %}
	所有条件都不满足执行的代码块
{% endif %}
num  = 18
{% if num >= 18 %}
	<p>成年了</p>
{% elif num < 18 %}
	<p>未成年</p>
{% else %}
	<p>年龄写错了</p>
{% endif %}

image-20220306225033525

4.4 for 与 if 混用

{% for 变量 in  %}
	{% iif判断语句 %}
        if表达式为真执行的代码块
    {% elif forloop.last %}
	   if表达式为真执行的代码块
	{% endif %}
{% endfor %}
list_ = ['aa', 'bb', 'cc', 'dd', 'dd']
    <!--下面写测试的模板语法-->
    {% for i in list_ %}
        {% if forloop.first %}
            <p> 第一个值: {{ i}} </p>
        {% elif forloop.last %}
           <p> 最后一个值: {{ i }} </p>
        {% endif %}
    {% endfor %}

image-20220306230131465

4.5 empty

for循环的可迭代对象为空时执行。
list_ = [1, 2]
{% for i in list_  %}
	<p> {{ i }} </p>
{% endfor %}
<empty>
    <p>3</p>
</empty>

image-20220306232023091

4.6 for遍历字典

for 变量字典 默认只能拿到键
模板语法中可
字典可以使用.keys   获取所有的键
字典可以使用.values 获取所有的值
字典可以使用.items  获取键值对
.
    dict_ = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
    {% for i in dict_.keys  %}
        <p> {{ i }} </p>
    {% endfor %}

    {% for i in dict_.values  %}
        <p> {{ i }} </p>
    {% endfor %}

    {% for i in dict_.items  %}
        <p> {{ i }} </p>
    {% endfor %}

image-20220306232813657

4.7 with起别名

在with语法内可以通过as起别名,一个别名代替一个模板语法取值语句。
别名快速的到前面复杂的模板语法中取值。

{% with 取值表达式 as 别名 %}
	{{别名}}
{% withend %}
    dict_ = {'name': ['you', {'小名': ['二狗子', '狗剩']}]}

    <p>{{ dict_.name.1.小名.1}}</p>
    {% with dict_.name.1.小名.1 as yourname %}
    <p>{{ yourname }}</p>
    <p>{{ yourname }}</p>
    {% endwith %}

image-20220306233655451

5. 自定义模板语法

过滤器、标签、inclusion_tag
必须步骤:
1.在app应用下创建一个名字叫templatetags文件夹。
2.在该文件夹内创建一个任意名称的.py文件
3.在该py文件内必须写下两个语句
	from django import template
	register = template.Library()
4. 前端先使用{% load 自动模板语法文件的名字 %}
5. {{ |name指定名字 }}  使用
0. 在app01 下创建templatetags文件夹
1. 在templatetags文件夹创建mytag.py
2. mytag.py文件内容:
    from django import template
    register = template.Library()

5.1 过滤器

* 自定义的过滤器函数最多只能有两个参数
# app01的templatetags 目录下的 my_delimit.py
from django import template

register = template.Library()


# register.过滤器(name='过滤器的名字')
@register.filter(name='my_filter')
def my_filter(num):
    # 编辑逻辑
    if num >= 18:
        msg = '成年人'
    elif num < 18:
        msg = '未成年'
    else:
        raise '请提供数据类型的数据!'
    return msg

# app01 下的 views.py 
# 4.index 模板语法测试
def index(request):
    num = 1
    return render(request, 'index.html', locals())
    <!--0.必须先导入文件-->    
    {% load my_delimit %}
	<!--1.使用-->    
    <p> {{ num|my_filter }}</p>

image-20220307001954626

自定义过滤器的函数只能有两个参数.
@register.filter(name='my_sum')
def my_sum(num1, num2):
    return num1 + num2
    <p> {{ num|my_sum:2 }}</p>

image-20220307002853806

5.2 标签

可以接受任意个参数,参数之间用空格分隔开。
类似于自定义函数。
@register.simple_tag(name='my_sum2')
def my_sum2(num1, num2, num3, num4):
    return num1+num2+num3+num4
    {% load my_delimit %}
    <p> {%  my_sum2 num1 2 3 4 %}</p>

image-20220307003643070

5.3 inclusion_tag

先定义一个方法,方法中指定一个模板页面.
在页面上调用该方法(可以传值)生成一些数据然后传递给模板页面.
之后将模板页面中渲染好的结果放到调用的位置

@register.inclusion_tag('模板页面.html')
@register.inclusion_tag('模板页面.html')
def  my_item(n):  # n 是多少就建多少个 第x项
    data = ['第{}项'.format(i) for i in range(n)]
    将函数的名称空间传递给 前端页面
    # print(data)
    return locals()  # 将函数的名称返回前端
['第{}项'.format(i) for i in range(n)]
列表生成器
['第1项', '第2项', ...]
<!-- 项目的 templates  文件 新建一个html文件 文件中只有以下内容,没有其他的东西-->
<!--模板页面-->
<ul>
    {% for i in data %}
        <li>{{ i }}</li>
    {% endfor %}
</ul>
<!-- 项目的 templates  文件 下的 index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法测试</title>
</head>
<body>
    <h1>模板语法测试</h1>
    <!--下面写测试的模板语法-->
    <!--0.先导入创建的自动模板语法的文件-->
    {% load my_delimit %}
    <!--调用-->
    {%  my_item 5 %}
</body>
</html>

image-20220307011239458

当html页面某一个地方需要参数才能够动态的渲染出来,
并在在多个页面上都需要使用到该局部,那么将该局部页面作为inclusion_tag形式。

6. 继承模板

很多的网站页面整体都大差不差,只是某一些局部在做变化.
那么相同的地方就可以使用同提个模板,不同的地方在稍稍修改.
模板页面 models.html
{% block 区域的名字 %}         
	被替换的区域
{% endblock %}

子页面 xxx.html
{% extends 'models.html' %}  继承模板页面
{% block 区域的名字 %}        引用
 	写新的代码替换
{% endblock %}
一般情况下会留有三块可以被修改的区域。
1. css区域
2. html区域
3. js 区域
模板页面上划定的区域多,拓展性就高.(如果太多也没必要)
每一个子页面都可以有自己独立的css代码html代码js代码。

{% block css %}         
	被替换的区域
{% endblock %}

{% block html %}         
	被替换的区域
{% endblock %}

{% block js %}         
	被替换的区域
{% endblock %}

7. 继承模板案例

7.1 路由层

项目下的urls.py 写路由和视图函数的对应关系.
from django.conf.urls import url
from django.contrib import admin
# 0. 导入 数图函数
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 1. 注册页面
    url(r'^register/', views.register),
    # 2. 登入页面
    url(r'^login/', views.login),
    # 3. 主页
    url(r'^home/', views.home)
]

7.2 视图层

app01 应用下views.py 写视图函数.
# 0. 导入Python 三板斧
from django.shortcuts import render, HttpResponse, redirect


# 1. 主页
def home(request):
    return render(request, 'home.html')


# 2. 注册
def register(request):
    return render(request, 'register.html')


# 3. 登入
def login(request):
    return render(request, 'login.html')

7.3 模板页面

home主页,也是模板页面
设置不继承的区域.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    <!--0. 动态获取令牌-->
    {% load static %}
    <!--1. 导入 jQuery-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--2. 导入 bootstrap css 文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--3. 导入 bootstrap js 文件-->
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    {% block css %}
    {% endblock %}
</head>
<body>
<!--4.页面布局-->
<div>
    <!--5. 导航条-->
    <div>
        <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="#">全栈开发</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="#">首页<span class="sr-only">(current)</span></a></li>
            <li><a href="#">我的笔记</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">学习链接<span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Python</a></li>
                <li><a href="#">前端</a></li>
                <li><a href="#">MySQL</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">博客园</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">CSND</a></li>
              </ul>
            </li>
          </ul>
          <form class="navbar-form navbar-left">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="在这看查询">
            </div>
            <button type="submit" class="btn btn-default">搜索</button>
          </form>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">收藏本页</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">状态选择<span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#"></a></li>
                <li><a href="#">隐身</a></li>
                <li><a href="#">免打扰</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">退出</a></li>
              </ul>
            </li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
    </div>
    <!--6. 栅格系统 4 / 8  container-fluid 占据全部视野-->
    <div class="container-fluid">
        <div class="row">
            <!--7.左边布局-->
          <div class="col-md-4">
              <!--7.1列表组-->
              <ul class="list-group">
                  <li class="list-group-item list-group-item-danger"><a href="/home/">主页</a></li>
                  <li class="list-group-item list-group-item-success"><a href="/register/">注册</a></li>
                  <li class="list-group-item list-group-item-info"><a href="/login/">登入</a></li>

              </ul>
          </div>
            <!--8.右边布局-->
          <div class="col-md-8">
              <!--8.1情境效果-->
              <div class="panel panel-primary">
                  <!--8.2带标题的面板-->
                  <div class="panel-heading">
                      <h3 class="panel-title">请看这里</h3>
                  </div>
                  <div class="panel-body">
                      <!--9.替换的内容-->
                      {% block content %}
                      <!--8.3巨幕-->
                      <div class="jumbotron">
                          <h1>学习入口</h1>
                          <p>欢迎你的登入!</p>
                          <p><a class="btn btn-primary btn-lg" href="#" role="button">进入</a></p>
                      </div>
                      {% endblock %}
                  </div>
              </div>
          </div>
        </div>
    </div>
</div>

<script>

    {% block js %}
        // js代码
        alert('主页面')
    {% endblock %}

</script>

</body>
</html>

7.4 继承模板

0. register.html   中继承home.html页面.  
1. login.html      中继承home.html页面.
<!--0.引用模板-->
{% extends 'home.html' %}

<!--css 局部修改-->
{% block css %}

{% endblock  %}

<!--html 局部修改-->
{% block content %}

{% endblock  %}


<!--js 局部修改-->
{% block js %}

{% endblock  %}

image-20220307171836053

2. 在浏览器中 127.0.0.1:8000/home  
3. 在浏览器中 127.0.0.1:8000/register  
4. 在浏览器中 127.0.0.1:8000/login

image-20220307172119295

* 修改模板的栅格 1 - 11 所有是有这个模板的页面都会跟着改变.

image-20220307175217644

7.5 注册页面

<!--0.引用模板-->
{% extends 'home.html' %}

<!--css 局部修改-->
{% block css %}
    <style>
        h1 {
            color: gold;
        }
    </style>
{% endblock  %}

<!--html 局部修改-->
{% block content %}
    <div>
        <form action="" method="post">
            <h1 class="text-center">注册页面</h1>
            <p>用户名称:
                <input type="text" name="username" class="form-control">
            </p>
            <p>用户密码:
                <input type="password" name="password" class="form-control">
            </p>
            <input type="submit" value="注册" class="btn btn-block btn-info">
        </form>
    </div>
{% endblock  %}


<!--js 局部修改-->
{% block js %}
    alert('注册页面')
{% endblock  %}

7.6 登入界面

<!--0.引用模板-->
{% extends 'home.html' %}

<!--css 局部修改-->
{% block css %}
    <style>
        h1 {
            color:chartreuse;
        }
    </style>
{% endblock  %}

<!--html 局部修改-->
{% block content %}
    <div>
        <form action="" method="post">
            <h1 class="text-center">登入页面</h1>
            <p>用户名称:
                <input type="text" name="username" class="form-control">
            </p>
            <p>用户密码:
                <input type="password" name="password" class="form-control">
            </p>
            <input type="submit" value="登入" class="btn btn-block btn-info">
        </form>
    </div>
{% endblock  %}


<!--js 局部修改-->
{% block js %}
    alert('登入页面')
{% endblock  %}
0. 在浏览器中 127.0.0.1:8000/home  
1. 在浏览器中 127.0.0.1:8000/register  
2. 在浏览器中 127.0.0.1:8000/login

image-20220307175422506

8. 导入模板

将页面当作是一个模块,需要的时候直接导入。
0. 项目下 路由层 urls.py 添加代码
1. app01 应用下 视图层 views.py 添加代码
2. 项目下 templates 目录  models.html 写模板
3. 项目下 templates 目录  index.html 引用模板
    # 4. 索引
    url(r'^index', views.index)
# 4. 目录索引
def index(request):
    return render(request, 'index.html')
<!--models.html 模板-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    <!--0. 动态获取令牌-->
    {% load static %}
    <!--1. 导入 jQuery-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--2. 导入 bootstrap css 文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--3. 导入 bootstrap js 文件-->
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    {% block css %}
    {% endblock %}
</head>
<body>
<!--4. 巨幕-->
<div class="jumbotron">
  <h1>Hello, world!</h1>
  <p>...</p>
  <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>

</body>
</html>
<!--index.html 模板-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试页面</title>
</head>
<body>
<!--导入模板-->
{% include 'models.html' %}
</body>
</html>

image-20220307185405286