赞
踩
在实际应用中,会使用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())
<!--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>
<!--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中:-->
<!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.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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
对基于include的策略来说,头/底部的包含很简单,困难的是中间部分
在此例中,每个页面都有1个<h1>My helpful timestamp site</h1>标题
但是这个标题不能放在header.html 中,因为每个页面的标题是不同的
如果将其包含在头部,就需要包含标题,但这样无法在每个页面进行定制
Django的模板继承系统解决了这些问题:可以将其视为include策略的逆向思维版本;你可以对那些不同的代码段进行定义,而不是对共同的代码段进行定义
<!--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框架文档,将在本站点的所有页面中被使用;子模板的作用就是重载/添加/保留那些块的内容
{% 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 %}
这样每个模板就只包含自己独有的代码,相同的部分直接套用模板,减少了冗余
加载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 %},父模板将无从得知要使用哪个块的内容
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。