django 学习笔记-模板

模板

在工作中为了更好的展示数据给用户,所以都会使用html+css+js实现网页排版效果,但是很多开发人员并不能做到既擅长服务端开发又擅长前端开发的,当然,即便有,那这个开发人员的工资也不会低,而且同等条件下,1个人干活是怎么也比不过2个人的。所以,怎么让服务端的数据更好的展示到客户端,这就成为问题了。

模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。

Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)。

DTL官方文档: https://docs.djangoproject.com/zh-hans/3.2/topics/templates/

要在django框架中使用模板引擎把视图中的数据更好的展示给客户端,需要完成3个步骤:

  1. 在项目配置文件中指定保存模板文件的模板目录templates。一般模板目录都是设置在项目根目录或者主应用目录下。

  2. 视图中基于django提供的渲染函数绑定模板文件index.html和需要展示的数据变量

  3. 在模板目录下创建对应的模板文件(html文件),并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。

配置模板目录

在当前项目根目录下创建了模板目录templates. 然后在settings.py, 模板相关配置,找到TEMPLATES配置项,填写DIRS设置模板目录: BASE_DIR / "templates",

# 模板引擎配置
TEMPLATES = [
    {
        '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',
            ],
        },
    },
]

先创建一个子应用来演示模板的应用

python manage.py startapp tem

然后再在主应用的settings.py中,注册子应用,代码

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tem',   # 开发者创建的子应用,这里填写就是子应用的导包路径
]

在子应用目录下创建urls.py子路由文件,代码:

"""tem子应用路由"""
from django.urls import path, re_path
from . import views

urlpatterns = [
	# ....
]

总路由的urls.py中加载子应用的路由urls.py,代码:

from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    # path("路由前缀/", include("子应用目录名.路由模块"))
    path("tem/", include("tem.urls")),
    

视图中加载模板

加载视图模板

在刚刚创建的子应用tem/views中加载模板tem.views.index 代码:

from django.shortcuts import render

def index(request):
     # 要显示到客户端的数据
	name = "hello DTL!"
    # return render(request, "模板文件路径",context={字典格式:要在客户端中展示的数据})
	return render(request, "index.html",context={"name":name})
# 也可以简写context,直接写字典格式
	return render(request, "index.html",{"name":name})
    

在templates模板目录下创建的index.html文件中,代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>来自模板的内容</h1>
    <p>输出变量name的值:{{ name }}</p>
</body>
</html>

完成了模板设置的3个步骤以后,就可以把视图绑定到子路由中.tem.urls.py,

代码:

"""子应用路由"""
from django.urls import path, re_path
from . import views

urlpatterns = [
    path("index", views.index),
]

在浏览器中访问:

render函数内部本质

img-20210530032914557

from django.shortcuts import render
from django.template.loader import get_template
from django.http.response import HttpResponse

def index2(request):
	name = "hello world!"
	#(1). 初始化模板,读取模板内容,实例化模板对象
    # get_template会从项目配置中找到模板目录,我们需要填写的参数就是补全模板文件的路径
	template = get_template("index.html")
	# (2). 识别context内容, 和模板内容里面的标记[标签]替换,针对复杂的内容,进行正则的替换
	context  = {"message": name}
	content = template.render(context, request) # render中完成了变量替换成变量值的过程,这个过程使用了正则。
	print(content)
	# (3). 通过response响应对象,把替换了数据的模板内容返回给客户端
	return HttpResponse(content)

         
    ## render函数一步完成上面的3步, context内容的简写:
def index3(request):
    data = {}
    data["name"] = "xiaoming"
    data["message"] = "你好!"
    return render(request,"index3.html", data)

def index4(request):
    name = "xiaohui"
    message = "QQ=>123456"
    return render(request,"index3.html", locals())

相关扩展

# 1. DTL模板文件与普通html文件的区别在哪里?
	DTL模板文件是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端。

 
# 2. 开发中,我们一般把开发中的文件分2种,分别是静态文件和动态文件。
静态文件,数据保存在当前文件,不需要经过任何处理就可以展示出去。
         普通html文件,图片,视频,音频等这一类文件叫静态文件。
动态文件,数据并不在当前文件,而是要经过服务端或其他程序进行编译转换才可以展示出去。
         编译转换的过程往往就是使用正则或其他技术把文件内部具有特殊格式的变量转换成真实数据。
         动态文件,一般数据会保存在第三方存储设备,如数据库中。
		django的视图,模板文件,就属于动态文件。

# 3. 除了render,django还提供了一个render_to_string函数 ,可以将函数结果提供给 HttpResponse直接返回给客户端。
# 代码参考如下:
from django.http.response import HttpResponse
from django.template.loader import render_to_string
def index(request):
    # 要显示到客户端的数据
    name = "hello DTL!"
    tpl_content = render_to_string('index.html', {"name":name})
    return HttpResponse(tpl_content)

模板语法

Django的DTL或jinja模板引擎提供的语法有3种格式不同的语法,分别是变量,标签,过滤器

"""变量"""
{{ 变量 }}

"""标签"""
{% 标签名 %}
{% 开始标签 %} {% 结束标签 %}

"""过滤器"""
# 本质就是函数[可以是python函数,也可以是开发者自定义函数]
# 单个无参数过滤器,变量默认作为过滤器的第1个参数,过滤器中return的内容作为结果被输出
{{ 变量 | 过滤器 }}
# 单个有参数过滤器,参数1是变量,英文冒号后面跟着的参数按顺序依次使用英文逗号排列
{{ 变量 | 过滤器:参数2,参数3,.... }}
# 多个无参数过滤器,每个 | (竖杠) 左边的内容作为右边过滤器的默认第1个参数
{{ 变量 | 过滤器1 | 过滤器2 | 过滤器3 | .....  }}
# 多个有参数过滤器,每个过滤器的参数1是 竖杠作为结果。最后一个过滤器返回的结果被输出
{{ 变量 | 过滤器1:参数2,参数3,....  | 过滤器2:参数2,参数3,....  | .... }}

变量

子应用视图代码,tem/views.py代码:

def index5(request):
    name = "root"
    age = 13
    sex = True
    lve = ["swimming", "shopping", "coding", "game"]
    bookinfo = {"id": 1, "price": 9.90, "name": "python3天入门到挣扎", }
    book_list = [
        {"id": 10, "price": 9.90, "name": "python3天入门到挣扎", },
        {"id": 11, "price": 19.90, "name": "python7天入门到垂死挣扎", },
    ]
    return render(request, 'index5.html', locals())

模板文件templates/index5,html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>来自模板的内容</h1>
    <p> 输出变量name的值:{{ name}}</p>
    <p> age : {{age }}</p>
    <p> sex : {{ sex }}</p>
    <p> 列表lve的成员</p>
    <p> lve0 : {{ lve.0 }}</p>
    <p> lve1 : {{ lve.1 }}</p>
    <p> lveLast : {{ lve | last }}</p>

    <p> 字典bookinfo的成员</p>
    <p> id= {{ bookinfo.id }}</p>
    <p> price = {{ bookinfo.price }}</p>

    <p> 复杂列表book——list的成员</p>
    <p> id = {{ book_list.0.id }}</p>
    <p> price = {{ book_list.1.price }}</p>
</body>
</html>

tem/urls.py代码:

"""子应用路由"""
from django.urls import path, re_path
from . import views

urlpatterns = [
	# ....
    path("index5", views.index5),
]

标签

文档:https://docs.djangoproject.com/zh-hans/3.2/ref/templates/builtins/#ref-templates-builtins-tags

if 判断语句

视图代码tem/views.py

def index6(request):
    name = "xiaoming"
    age = 19
    sex = True
    lve = ["swimming", "shopping", "coding", "game"]
    user_lve = "sleep"
    bookinfo = {"id": 1, "price": 9.90, "name": "python3天入门到挣扎", }
    book_list = [
        {"id": 10, "price": 9.90, "name": "python3天入门到挣扎", },
        {"id": 11, "price": 19.90, "name": "python7天入门到垂死挣扎", },
    ]
    return render(request, 'index6.html', locals())

模板代码,templates/index6.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% if age < 18 %}
        <p> 你还没成年,不能访问我的网站!</p>

    {% endif %}

    {% if name == "root" %}
        <p> 超级用户,欢迎回家!</p>
    {% else %}
        <p> 你好,欢迎来到xx网站!</p>
    {% endif %}


    {% if user_lve == lve.0 %}
        <p>那么巧,你喜欢游泳,海里也能见到你</p>
    {% elif user_lve == lve.1%}
        <p>那么巧,你也来收快递呀?</p>
    {% elif user_lve == lve.2 %}
        <p> 那么巧,你也来here</p>
    {% else %}
        <p>看来我们没有缘分</p>
    {% endif %}
</body>
</html>

子路由代码,tem/urls.py代码:

"""子应用路由"""
from django.urls import path, re_path
from . import views

urlpatterns = [
	# ....
    path("index6", views.index6),
]
for循环语句

视图代码,tem/views.py代码:

ef index7(request):
    book_list1 = [
        {"id": 11, "name": "python基础入门", "price": 130.00},
        {"id": 17, "name": "Go基础入门", "price": 230.00},
        {"id": 23, "name": "PHP基础入门", "price": 330.00},
        {"id": 44, "name": "Java基础入门", "price": 730.00},
        {"id": 51, "name": "C++基础入门", "price": 300.00},
        {"id": 56, "name": "C#基础入门", "price": 100.00},
        {"id": 57, "name": "前段基础入门", "price": 380.00},
    ]

    return render(request,"index7.html",locals())

模板文件代码,templates/index7.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table width=" 800" align="center" border="1">
        <tr>
            <td> 序号</td>
            <td> id</td>
            <td> 标题</td>
            <td> 价格 </td>
        </tr>
	{# 1.第一种循环模式:直接对列表遍历,获取每一个字典book #}
{#        {% for book in book_list1 %}#}
{#            <tr>#}
{#                <td>{{ book.id}}</td>#}
{#                <td>{{ book.name }}</td>#}
{#                <td>{{ book.price }}</td>#}
{#            </tr>#}
{#        {% endfor %}#}

  {# 2.对列表里面的每一个字典进行解包#}
{#        {% for book in book_list1 %}#}
{#            <tr>#}
{#                {% for filed,value in book.items  %}#}
{#                    <td>{{ filed }} == {{ value }}</td>#}
{#                {% endfor %}#}
{##}
{#            </tr>#}
{##}
{#        {% endfor %}#}
	{# 3. 对循环结果进行条件判断#}
{#        {% for book in book_list1 %}#}
{#            <tr>#}
{#                <td>{{ book.id }}</td>#}
{#                <td>{{ book.name }}</td>#}
{#                {% if book.price > 200 %}#}
{#                    <td bgcolor="#dc143c">{{ book.price }}</td>#}
{#                {% else %}#}
{#                    <td>{{ book.price }}</td>#}
{#                {% endif %}#}
{#            </tr>#}
{#        {% endfor %}#}
	{#逆向循环遍历数据 ,加 reversed #}
{#        {% for book in book_list1 reversed %}#}
{#            <tr>#}
{#                <td>{{ book.id }}</td>#}
{#                <td>{{ book.name }}</td>#}
{#                {% if book.price > 200 %}#}
{#                    <td bgcolor="aqua"> {{ book.price }}</td>#}
{#                {% else %}#}
{#                    <td>{{ book.price }}</td>#}
{#                {% endif %}#}
{#            </tr>#}
{#        {% endfor %}#}
	{#循环次数#}
        {% for book in book_list1  %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ forloop.counter0 }}</td>
                <td>{{ forloop.revcounter }}</td>
                <td>{{ forloop.revcounter0 }}</td>
                <td>{{ forloop.first }}</td>
{#                <td>{{ forloop.last }}</td>#}
{#                <td>{{ book.id }}</td>#}
{#                <td>{{ book.name }}</td>#}
{#                {% if book.price > 200 %}#}
{#                    <td bgcolor="#d2691e">{{ book.price }}</td>#}
{#                {% else %}#}
{#                    <td>{{ book.price }}</td>#}
{#                {% endif %}#}
            </tr>
        {% endfor %}
    
    </table>

</body>
</html>

子路由代码,tem/urls.py代码:

"""子应用路由"""
from django.urls import path, re_path
from . import views

urlpatterns = [
	# ....
    path("index7", views.index7),
]

循环中, 模板引擎提供的forloop对象,用于给开发者获取循环次数或者判断循环过程的.

属性 描述
forloop.counter 显示循环的次数,从1开始
forloop.counter0 显示循环的次数,从0开始
forloop.revcounter0 倒数显示循环的次数,从0开始
forloop.revcounter 倒数显示循环的次数,从1开始
forloop.first 判断如果本次是循环的第一次,则结果为True
forloop.last 判断如果本次是循环的最后一次,则结果为True
forloop.parentloop 在嵌套循环中,指向当前循环的上级循环

过滤器filter

filter本质是一个函数,这种函数允许我们直接在模板中使用,使用过滤器的情况一般是希望在模板中对数据进行格式化处理或者对数据进行规范输出和调整.

文档: https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#ref-templates-builtins-tags

内置过滤器

safe声明当前视图提供的数据中,html代码不需要进行实体字符转义

如果来自客户端的留言等消息,在是否使用safe时,一定要考虑清楚,可以提前清楚script等不安全的标签.

常用过滤器
过滤器 用法 代码
last 获取列表/元组的最后一个成员 {{liast | last}}
first 获取列表/元组的第一个成员 {{list|first}}
length 获取数据的长度 {{list | length}}
defualt 当变量没有值的情况下, 系统输出默认值, {{str|default="默认值"}}
safe 让系统不要对内容中的html代码进行实体转义 {{htmlcontent| safe}}
upper 字母转换成大写 {{str | upper}}
lower 字母转换成小写 {{str | lower}}
title 每个单词首字母转换成大写 {{str | title}}
date 日期时间格式转换 `{{ value
cut 从内容中截取掉同样字符的内容 {{content | cut:"hello"}}
list 把内容转换成列表格式 {{content | list}}
escape 把内容中的HTML特殊符号转换成实体字符 {{content | escape }}
filesizeformat 把文件大小的数值转换成单位表示 {{filesize | filesizeformat}}
join 按指定字符拼接内容 {{list| join("-")}}
random 随机提取某个成员 {list | random}}
slice 按切片提取成员 {{list | slice:":-2"}}
truncatechars 按字符长度截取内容 {{content | truncatechars:30}}
truncatewords 按单词长度截取内容 {{content | truncatewords:30}}
过滤器的使用

视图代码,tem/views.py代码:

ef index10(request):
    # 内置过滤器的使用
    content = "<img src='https://www.oldboyedu.com/static/images/header/logo.png'>"
    from datetime import datetime
    pub_date = datetime.now()
    message = "中文hello, world"

    return render(request,"index10.html",locals())
    

模板代码,templates/index10.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body> 
    	{# safe 让系统不要对内容中的html代码进行实体转义 #}
    <p> {{ content | safe }}</p>
    
    	{# date 日期时间格式转换 #}
{# 过滤器本质就是函数,但是模板语法不支持小括号调用,所以需要使用:号分割参数 #}
    <p> {{ pub_date | date:"Y-m-d H:i:s" }}</p>
    
    	{# 当变量没有值的情况下, 系统输出默认值 #}
    <p> {{ message | default:"佚名"}}</p>
    	 
    	{# 一个数据可以连续调用多个过滤器 #}
    <p> {{ message | slice:'::-1' | upper }}</p>    
    <p> {{ message | truncatechars:8 | upper }}</p>
    
</body>
</html>

虽然官方已经提供了许多内置的过滤器给开发者,但是很明显,还是会有存在不足的时候。

例如:希望输出用户的手机号码时, 13912345678 ---->> 139****5678

自定义过滤器 customer filter

要声明自定义过滤器并且能在模板中正常使用,需要完成3个步骤:

( 1 ) 确保当前需要使用过滤器的子应用已经注册到了主应用settings.py文件中的INSTALLED_APPS中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tem',   # 开发者创建的子应用,这里填写就是子应用的注册路径
]

( 2 ) 编写过滤器,必须在子应用下的templatetags(在子应用下创建含有__init__配置文件的包)包里面创建自定义过滤器的python文件,

在子应用下创建templatetags包[必须包含__init__.py], 在包目录下创建任意的过滤器函数py文件

自定义过滤器函数必须被 template.register进行装饰使用.而且过滤器函数所在的模块必须在templatetags包里面保存

过滤器tem/templatetags/my_filters.py代码:

from django import template    # 引入template
register = template.Library()    # 实例化register

#  自定义过滤器
# 过滤器函数装饰器
@register.filter("sex")  # 这里的参数"sex"就是自定义过滤器的名字
def check_sex(content):  #  过滤器必须提供一个以上的参数给模板调用
    if int(content):
        return "男性"
    return "女性"

子应用视图代码:

def index11(request):
    user_list = [
        {"id": 10, "name": "xiaomin", "money": 1000, "sex": 0},
        {"id": 12, "name": "xiaoming", "money": 800, "sex": 1},
        {"id": 13, "name": "xiaohui", "money": 200.5, "sex": 1},
        {"id": 14, "name": "xiaobai", "money": 180.75, "sex": 1},
    ]

    return  render(request,"index11.html",locals())

子路由代码:

rom django.urls import path,re_path

from . import views

urlpatterns = [
   # ...
    path("index11",views.index11)
    
]

( 3 ) 在模板中通过load标签加载当前子应用已经声明的过滤器函数,load标签文档只用最好写在模板开头第一行

模板代码,templates/index11.html代码:

// 在需要使用的模板文件中顶部使用load标签加载过滤器文件my_filters.py并调用自定义过滤器{% load "自定义过滤器文件名" %}

{% load my_filters %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table width="800" align="center" border="1">
        <tr>
            <td>id</td>
            <td>姓名</td>
            <td>性别</td>
            <td>钱包</td>
        </tr>

        {% for user in user_list  %}
            <tr>
                <td>{{ user.id }}</td>
                <td>{{ user.name}}</td>
                <td>{{ user.sex | sex }}</td>  // 使用自定义的过滤器
                <td>{{ user.money }}</td>
            </tr>

        {% endfor %}

    </table>
</body>
</html>


作业:

  1. 在上面代码的基础上,给后台数据增加mobile,自定义一个隐藏用户手机信息的过滤器

    13312345678—-> {{ user.mobile | mobile }} ——>> 1335678

  2. 在上面代码的基础上,输出用户信息时,使用过滤器把money进行格式化,保留小数点2位。

    100 —–> {{user.money | fixed:2}} —>> 100.00

    99.3 —–> {{user.money | fixed:2}} —>> 99.30

    99.352 —–> {{user.money | fixed:2}} —>> 99.36

视图代码:

def index11(request):
    user_list = [
        {"id": 10, "name": "xiaomin", "money": 1000, "sex": 0 , "mobile":"18394219902"},
        {"id": 12, "name": "xiaoming", "money": 800, "sex": 1 , "mobile":"18394219902"},
        {"id": 13, "name": "xiaohui", "money": 200.5, "sex": 1, "mobile":"18394219902"},
        {"id": 14, "name": "xiaobai", "money": 180.75, "sex": 1, "mobile":"18394219902"},
    ]

    return  render(request,"index11.html",locals())

模板templates/index11.html代码:

% load my_filters %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table width="800" align="center" border="1">
        <tr>
            <td>id</td>
            <td>姓名</td>
            <td>性别</td>
            <td>钱包</td>
            <td>电话</td>
        </tr>

        {% for user in user_list  %}
            <tr>
                <td>{{ user.id }}</td>
                <td>{{ user.name}}</td>
                <td>{{ user.sex | sex }}</td>
                <td>{{ user.money | money}}</td>
                <td>{{ user.mobile | mobile }}</td>
            </tr>

        {% endfor %}

    </table>


</body>
</html>

浏览器实现效果:

image-20210531174242146

模板继承

模板分离

image-20210531111100929

django中提供了{% include "模板文件名" %} 标签模板分离技术

在模板目录templates下创建一个common公共project, 在此下面可以创建任意的公共模板html文件,以便于视图模板文件用{% include "common/模板名"%} 来引用这里的公共模板.

文档https://docs.djangoproject.com/zh-hans/2.2/ref/templates/language/#template-inheritance

视图tem/views.py,代码:

from django.shortcuts import render

def index12(request):
    """模板分离"""
    return render(request,"index12.html",locals())


def index13(request):
    """ 模板分离- 重复用模板代码"""
    return render(request,"index13.html",locals())

子路由tem/urls.py,代码:

rom django.urls import path,re_path

from . import views

urlpatterns = [
 #...
    path("index12",views.index12),
    path("index13",views.index13)
]

公共模板,templates/common/head.html,代码:

// 文档格式可以不写:

<div>head.html的公共头部</div>

公共模板,templates/commonfooter.html,代码:

 <div>footer.html公共脚部 </div>

公共模板,templates/common/slide.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div> slide,html的侧栏部分</div>
</body>
</html>

视图对应的模板, templates/index12.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% include "common/head.html" %}   //->这里引用公共头部模板
    <div >
        <div> index12.html的主体内容</div>
        {% include "common/slide.html" %}  //-> 引用公共侧栏部分模板
    </div>
    {% include "common/footer.html" %}  //-> 引用公共脚部模板
</body>
</html>

视图对应的模板, templates/index13.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% include "common/head.html" %}   //->这里引用公共头部模板
    <div >
        <div> index13.html的主体内容</div>
        {% include "common/slide.html" %}  //-> 引用公共侧栏部分模板
    </div>
    {% include "common/footer.html" %}  //-> 引用公共脚部模板
</body>
</html>

浏览器效果:

image-20210531195739826

其实模板分离,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.

因此, 大部分框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承 给开发者

模板继承

就是我们的子模板在显示时继承了父模板的公共内容:

子模板: 就是视图对应的模板文件

父模板: 就是在templates下面建立的common目录下的base.html模板文件

在父模板base.htm中,用{% block 变量名 % } 声明的部分都是可以在子应用中自定义的内容,但是自定义时,变量名必须和父模板的变量名保持一致; 如果要引用父模板原来的内容,就用{ { block. super } }标签引用,再加上自己自定义内容.如果不引用就不加该标签,直接{% block 变量名 % }自定义内容.

1 . 显示子模板的时候,继承父模板的公共内容:

{ % extends "common/base.html" %}

视图代码, tem/views.py, 代码:

from django.shortcuts import render

def index14(request):
    """模板继承"""
    return render(request,"index14.html",locals())

def index15(request):
    """模板继承"""
    return render(request,"index15.html",locals())

路由tem/urls.py,代码:

rom django.urls import path,re_path

from . import views

urlpatterns = [
 #...
    path("index14",views.index14),
    path("index15",views.index15)
]

父模板templates/common/base.html,代码:

### 在父模板中用标签{%block %}声明的都是子模板可以改动的,可以自定义的部分.###

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% block style %}     # 可改动的可定义的
    {% endblock style %}
</head>
<body>
    {% block header %}
        <div> base.html的公共头部</div>  # 可改动的可自定义的
    {% endblock header %}

    <div>
        {% block content %}
            <div> 公共base.html的主体代码</div>   # 可改动的可自定义的
        {% endblock content%}

        <div>base.html侧栏效果</div>  ## 这里没有用{%block%}声明的就是子模板不能改动自定义的部分.##
    </div>
    <div>base.html的公共脚部分</div>  ## 这里没有用{%block%}声明的就是子模板不能改动自定义的部分.##
</body>
</html>

子模板templates/index14.html ,代码:

{% extends "common/base.html" %}

{% block content %}  
    {{ block.super }}
    <div> index14.html子模板的主体代码</div>
{% endblock %}

## 继承了父模板的公共部分,只独立设置了主体部分,而且haunt引用了父模板的主体,再加上自己的.其他的部分都是继承父模板的部分.##

浏览器效果:

子模板templates/index15.html ,代码:

{% extends "common/base.html" %}

{% block style %}
    <style>
    body{
        background-color: blueviolet;
    }
    </style>
{% endblock style%}

{% block content %}
    <div> index15.html的主体部分代码</div>  ## 主体部分只用自定义的##
{% endblock %}

{% block header %}
    {{ block.super }}    ## 引用父模板的头部## 
{% endblock header%}

浏览器效果:

posted @ 2021-05-31 22:46  豆#豆  阅读(128)  评论(0)    收藏  举报