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.实例:


{% load staticfiles %}

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <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 LOGINh1>
	        	{% include 'list.html' %}
        div>
    div>
body>
html>





<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <style>
        * {
            margin:0;
        	padding:0;
        }
        h1,h2,h3,h4 {
            color:red;
        }
    style>
head>
<body>
    <h1>H1h1>
    <h2>H2h2>
    <h3>H3h3>
    <h4>H4h4>
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继承:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <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 LOGINh1>
        div>
    div>
body>
html>


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <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继承:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <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 LOGINh1>
	        {% endblock %}
        div>
    div>
body>
html>

{% extends 'index.html' %}
{% block content %}
    {% block.super %}
    {% for student in students_list %}
        <h2>学生:{{ student }}h2>
    {% endfor %}
{% endblock %}

三.详解

  • 为current_datetime.html创建模板:


<html lang="en">
<head>
    <title>The current timetitle>
head>
<body>
    <h1>My helpful timestamp siteh1>
    <p>It is now {{ current_date }}p>
    <hr>
    <p>Thanks for visiting my sitep>
body>
html>
  • 再为hours_ahead创建另1个模板:


<html lang="en">
<head>
    <title>Future timetitle>
head>
<body>
    <h1>My helpful timestamp siteh1>
    <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:

<html lang="en">
<head>
  • 或把底部保存到文件footer.html:
<hr>
    <p>Thanks for visiting my site.p>
body>
html>
  • 问题:
对基于include的策略来说,头/底部的包含很简单,困难的是中间部分
在此例中,每个页面都有1个

My helpful timestamp site

标题 但是这个标题不能放在header.html 中,因为每个页面的标题是不同的 如果将其包含在头部,就需要包含标题,但这样无法在每个页面进行定制

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

  1. 定义基础模板,该框架之后将被子模板继承:


<html lang="en">
<head>
    <title>{% block title %}{% endblock %}title>
head>
<body>
    <h1>My helpful timestamp siteh1>
    {% 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 %},父模板将无从得知要使用哪个块的内容

你可能感兴趣的:(python,web,django)