Django框架 模板继承

在实际应用中,会使用Django模板系统来创建整个网站
这就带来1个常见的Web开发问题:
在整个网站中,如何减少共用页面区域(如站点导航)引起的冗余代码?

传统做法是使用Server端的includes:
可以在HTML页面中使用该指令将1个网页嵌入到另1个网页中
事实上,Django通过{% include %}支持了该方法

但是用Django解决此类问题的首选方法是更优雅的策略—extend模板继承

一.include(添加):通过{% include %}标签
1.语法:

{% include name %} :模板中放入其它的模板的内容
#将1个网页(name指定的网页)的的内容嵌入到另1个网页(使用该标签的网页)中
  #参数说明:
    name:要添加的模板名称;可以是变量或用单/双引号硬编码的str

#注意:
多个模板中出现相同代码时,就应考虑使用该标签来减少重复
在引入前加{% load staticfiles %}来加载静态文件,然后{% include name %}添加模板

2.实例:

<!--Template下的index.html中:-->
{% load staticfiles %}<!--加载静态文件-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        .nav {
            line-height:40px;
            width:100%;
            background-color:#2459a2;
            color:white;
            font-size:20px;
            text-align:center;
		}
        .left {
            width:20%;
            min-height:600px;
            overflow:auto;
            background-color:lightgrey;
        }
        .manage {
            text-align:center;
            padding:20px 0;
            margin:20px 0;
            font-size:18px;
        }
        .content {
            width:70%;
            min-height:600px;
        }
        a {
            text-decoration:none;
        }
        .left,.content {
            float:left;
        }
        h1 {
            text-align:center;
        }
    </style>
</head>
<body>
    <div class='outer'>
	    <div class='nav'>标题</div>
	    <div class='left'>
	        <div class='students manage'><a href='/student/'>学生管理</a></div>
	        <div class='teachers manage'><a href=''>教师管理</a></div>
			<div class='courses manage'><a href=''>课程管理</a></div>
			<div class='classes manage'><a href=''>班级管理</a></div>
        </div>
	    <div class='content'>
	        	<h1>WELCOME TO LOGIN</h1>
	        	{% include 'list.html' %}<!--导入模板list.html-->
        </div>
    </div>
</body>
</html>

<!--###################################################-->

<!--Template下的list.html中:-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        h1,h2,h3,h4 {
            color:red;
        }
    </style>
</head>
<body>
    <h1>H1</h1>
    <h2>H2</h2>
    <h3>H3</h3>
    <h4>H4</h4>
</body>
</html>

二.extends(继承):通过{% extends %}标签
1.语法:

{% extends name %}:继承模板
  #参数说明:
    name:指定要继承的模板;可以是变量或用单/双引号硬编码的str
{% block name %}:定义块,继承模板的页面可以修改块中的内容
  #参数说明:
    name:指定该{% block %}块的名字
{% endblock %}:表示该{% block %}块结束

#本质上来说,模板继承就是先构造1个基础框架模板
#然后在其子模板中对其包含的公用部分和定义块进行重载

2.实例:

#url.py中:
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns=[
    url(r'^admin',admin.site.urls),
    url(r'backend',views.backend),
    url(r'student',views.student),
]
#app01下的views.py中:
from django.shortcuts import render

def backend(req):
    return render(req,'index.html')

def student(req):
    students_list=['zzz','zeq','kt','cjl','wxh','hm']
    return render(req,'student.html',locals())
  • 不使用extends继承:
<!--Template下的index.html中:-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        .nav {
            line-height:40px;
            width:100%;
            background-color:#2459a2;
            color:white;
            font-size:20px;
            text-align:center;
		}
        .left {
            width:20%;
            min-height:600px;
            overflow:auto;
            background-color:lightgrey;
        }
        .manage {
            text-align:center;
            padding:20px 0;
            margin:20px 0;
            font-size:18px;
        }
        .content {
            width:70%;
            min-height:600px;
        }
        a {
            text-decoration:none;
        }
        .left,.content {
            float:left;
        }
        h1 {
            text-align:center;
        }
    </style>
</head>
<body>
    <div class='outer'>
	    <div class='nav'>标题</div>
	    <div class='left'>
	        <div class='students manage'><a href='/student/'>学生管理</a></div>
	        <div class='teachers manage'><a href=''>教师管理</a></div>
			<div class='courses manage'><a href=''>课程管理</a></div>
			<div class='classes manage'><a href=''>班级管理</a></div>
        </div>
	    <div class='content'>
	        <h1>WELCOME TO LOGIN</h1>
        </div>
    </div>
</body>
</html>
<!--Template下的student.html中:-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        .nav {
            line-height:40px;
            width:100%;
            background-color:#2459a2;
            color:white;
            font-size:20px;
            text-align:center;
		}
        .left {
            width:20%;
            min-height:600px;
            overflow:auto;
            background-color:lightgrey;
        }
        .manage {
            text-align:center;
            padding:20px 0;
            margin:20px 0;
            font-size:18px;
        }
        .content {
            width:70%;
            min-height:600px;
        }
        a {
            text-decoration:none;
        }
        .left,.content {
            float:left;
        }
        h1 {
            text-align:center;
        }
    </style>
</head>
<body>
    <div class='outer'>
	    <div class='nav'>标题</div>
	    <div class='left'>
	        <div class='students manage'><a href='/student/'>学生管理</a></div>
	        <div class='teachers manage'><a href=''>教师管理</a></div>
			<div class='courses manage'><a href=''>课程管理</a></div>
			<div class='classes manage'><a href=''>班级管理</a></div>
        </div>
	    <div class='content'>
	        {% for student in students_list %}
	            <h2>学生:{{student}}</h2>
	        {% endfor %}
        </div>
    </div>
</body>
</html>
  • 使用extends继承:
<!--Template下的index.html中:-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        .nav {
            line-height:40px;
            width:100%;
            background-color:#2459a2;
            color:white;
            font-size:20px;
            text-align:center;
		}
        .left {
            width:20%;
            min-height:600px;
            overflow:auto;
            background-color:lightgrey;
        }
        .manage {
            text-align:center;
            padding:20px 0;
            margin:20px 0;
            font-size:18px;
        }
        .content {
            width:70%;
            min-height:600px;
        }
        a {
            text-decoration:none;
        }
        .left,.content {
            float:left;
        }
        h1 {
            text-align:center;
        }
    </style>
</head>
<body>
    <div class='outer'>
	    <div class='nav'>标题</div>
	    <div class='left'>
	        <div class='students manage'><a href='/student/'>学生管理</a></div>
	        <div class='teachers manage'><a href=''>教师管理</a></div>
			<div class='courses manage'><a href=''>课程管理</a></div>
			<div class='classes manage'><a href=''>班级管理</a></div>
        </div>
	    <div class='content'>
	        {% block content %}#content是名字,可以随意起
	        	<h1>WELCOME TO LOGIN</h1>
	        {% endblock %}
        </div>
    </div>
</body>
</html>
<!--Template下的student.html中:-->
{% extends 'index.html' %}<!--从index.html继承模板;必须放在第1行-->
{% block content %}<!--修改{% block content %}的块中的内容-->
    {% block.super %}<!--获得index.html中这个块中的内容-->
    {% for student in students_list %}
        <h2>学生:{{ student }}</h2>
    {% endfor %}
{% endblock %}

三.详解

  • 为current_datetime.html创建模板:
<!--current_datetime.html中:-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>The current time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>It is now {{ current_date }}</p>
    <hr>
    <p>Thanks for visiting my site</p>
</body>
</html>
  • 再为hours_ahead创建另1个模板:
<!--hours_ahead.html中:-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>Future time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>In {{ hour_offset }} hour(s),it will be {{ next_time }}</p>
    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>

显然,上例中重复了大量HTML代码。对更典型的网站来说,有导航条/样式表/JS代码,必将填充更多冗余HTML

解决这个问题的include方案是找出模板中的共同部分,将其保存为不同的模板片段,然后在每个模板中进行include

  • 比如把模板头部的代码保存为header.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
  • 或把底部保存到文件footer.html:
<hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>
  • 问题:
对基于include的策略来说,头/底部的包含很简单,困难的是中间部分
在此例中,每个页面都有1个<h1>My helpful timestamp site</h1>标题
但是这个标题不能放在header.html 中,因为每个页面的标题是不同的
如果将其包含在头部,就需要包含标题,但这样无法在每个页面进行定制

Django的模板继承系统解决了这些问题:可以将其视为include策略的逆向思维版本;你可以对那些不同的代码段进行定义,而不是对共同的代码段进行定义

  1. 定义基础模板,该框架之后将被子模板继承:
<!--base.html中:-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr>
    <p>Thanks for visiting my site.</p>
    {% endblock %}
</body>
</html>

这个模板定义的HTML框架文档,将在本站点的所有页面中被使用;子模板的作用就是重载/添加/保留那些块的内容

  1. 使用{% block %}标签重载指定的块:
{% block %}标签告诉模板引擎,子模板可以重载标签中的部分

现在已经有了1个基本模板,通过修改基本模板创建current_datetime.html模板:

{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

创建hours_ahead模板:

{% extends "base.html" %}
{% block title %}Future time{% endblock %}
{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}

这样每个模板就只包含自己独有的代码,相同的部分直接套用模板,减少了冗余

  1. 如果想进行站点级别的修改,仅需修改base.html
  2. 加载current_datetime.html时的工作方式:
加载current_datetime.html模板时,模板引擎发现了{% extends %},注意到该模板是子模板
模板引擎立即装载其父模板,即本例中的 base.html
此时,模板引擎注意到base.html中的3个{% block %},并用子模板的内容替换这些block
因此,引擎将会使用在{% block title %}标签中定义的标题,对{% block content %}也是如此
所以,网页标题一块将由{% block title %}替换;同样地,网页的内容将由{% block content %}替换

注意:由于子模板并没有定义{% block footer %},模板系统将使用在父模板中定义的值
父模板{% block %}中的内容总是被当作一条退路

继承并不会影响到模板的上下文:

即任何处在继承树上的模板都可以访问传到模板中的每个模板变量

使用继承的一种常见方式是下面的三层法:

1.创建base.html模板:
在其中定义站点的主要外观感受,这些都是不常修改的部分

2.为网站的每个区域创建base_SECTION.html模板:
这些模板对base.html 进行拓展,并包含区域特定的风格与设计
如:base_photos.html 和 base_forum.html

3.为每种类型的页面创建独立的模板:
这些模板拓展相应的区域模板
如:论坛页面,图片库

这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容十分简单

一些使用extends模板继承的诀窍:

1.如果在模板中使用{% extends %},必须保证其为模板中的第1个模板标记,否则继承将不起作用

2.一般来说,基础模板中的{% block %}越多越好
子模板不必定义父模板中所有的代码块
因此可用合理的缺省值对代码块进行填充
然后只对子模板所需的代码块进行重定义
换句话说:钩子(Hook)越多越好

3.如果发觉自己在多个模板之间拷贝代码,就应该考虑将该代码段放到父模板的某个{% block %}中

4.如果需要访问父模板中的块的内容,使用{{ block.super }}标签,这个变量会表现出父模板中的内容
如果要在上级代码块的基础上添加内容,而不全部重载,就可以使用该变量

5.不允许在同1个模板中定义多个同名的{% block %}
限制的原因是:block 标签的工作方式是双向的
也就是说,{% block %}不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容
如果模板中出现了多个相同名称的{% block %},父模板将无从得知要使用哪个块的内容
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值