Django模板继承和静态文件
模板继承(extend)
Django模板引擎中最强大也是最复杂的部分就是模板继承了,模板继承可以让我们创建一个基本的"骨架"模板,它可以包含网页中的全部元素,并且可以定义能够被子模板覆盖的blocks。为了容易理解模板继承,我们先写一个模板:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>{% block title %}Replaceable template{% endblock %}</title>
- </head>
- <body>
- <div id="sidebar">
- {% block sidebar %}
- <ul>
- <li><a href="/">Home</a> </li>
- <li><a href="/blog">Blog</a> </li>
- </ul>
- {% endblock %}
- </div>
-
- <div id="content">
- {% block content %}{% endblock %}
- </div>
- </body>
- </html>
这个模板,我们把它叫做base.html,它定义了一个可以用于两列排版页面的简单HTML骨架。"子模板"可以用它们的内容填充空白的blocks。在这个例子中,block标签定义了三个可以被子模板内容填充的block,block告诉模板引擎:子模板可能会覆盖掉模板中的这些位置。
接下来,我们再写一个子模板:
- {% extends "polls/base.html" %} # 模板路径根据项目或者app的路径来写,笔者这里的模板位于app中
-
- {% block title %}Child template{% endblock %}
-
- {% block content %}
- {% for entry in blog_entries %}
- <h3>{{ entry.title }}</h3>
- <p>{{ entry.body }}</p>
- {% endfor %}
- {% endblock %}
extends标签是这里的关键,它告诉模板引擎这个模板继承了另一个模板。当模板系统处理这个模板时,首先定位父模板--此例中,就是"base.html"。那时模板引擎注意到base.html中的三个block标签,并用子模板中的内容来替换这些block。根据blog_entries的值,子模板输出的内容会是下面的内容:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <link rel="stylesheet" href="style.css" />
- <title>Child template</title>
- </head>
-
- <body>
- <div id="sidebar">
- <ul>
- <li><a href="/">Home</a></li>
- <li><a href="/blog/">Blog</a></li>
- </ul>
- </div>
-
- <div id="content">
- <h2>Entry one</h2>
- <p>This is my first entry.</p>
-
- <h2>Entry two</h2>
- <p>This is my second entry.</p>
- </div>
- </body>
- </html>
注意:子模板并没有定义sidebar block,所以系统使用了父模板中的值。父模板的{% block %}标签中的内容总是被用作备选内容。这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如:部分范围内的导航。
说明:
1.如果在模板中使用{% extends %}标签,它必须是模板中的第一个标签,其他的任何情况下,模板继承都将无法工作;
2.在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的block,所以,我们可以在大多数>block中填充合理的默认内容,然后,只定义我们需要的那一个。多一点钩子总比少一点好;
3.如果发现我们在大量的模板中复制内容,那就意味着我们应该把内容移动到父模板中的一个{% block %}中;
4.有时候,想在父模板的基础上再添加点其他的,而不是完全覆盖父模板的内容,那么我们只需要在想要填充的块里,再加上 >{{ block.super }}语句,我们就可以把父模板里的东西给留下来,如:
- 父模板中的
- {% block title %}Parent template{% endblock %}
-
- 如果我们只想子模板的结果是在后面添加一个!,则只需要在子模板中写成
- {% block title %}
- {{ block.super }}!
- {% endblock %}
5.为了更好的可读性,也可以给我们的 {% endblock %} 标签一个 名字 。例如:
- {% block content %}
- ...
- {% endblock content %}
6.在大型模板中,这个方法可以帮助我们清楚的看到哪个 {% block %}标签被关闭了;
最后,请注意我们不能在一个模版中定义多个相同名字的 block 标签。这个限制的存在是因为block标签的作用是“双向”的。这个意思是,block标签不仅提供了一个坑去填,它还在父模版中定义了填坑的内容。如果在一个模版中有两个名字一样的 block 标签,子模版的父模版将不知道使用哪个block的内容。
注意:模板一般放在app下的templates中,Django会自动去这个文件夹中找。但 假如我们每个app的templates中都有一个 index.html,当我们在views.py中使用的时候,直接写一个 render(request, 'index.html'),Django 能不能找到当前 app 的 templates 文件夹中的 index.html 文件夹呢?(答案是不一定能,有可能找错)
Django模板查找机制:Django 查找模板的过程是在每个 app 的 templates 文件夹中找(而不只是当前 app 中的代码,只在当前 app 的 templates 文件夹中找)。各个 app 的 templates 形成一个文件夹列表,Django 遍历这个列表,一个个文件夹进行查找,当在某一个文件夹找到的时候就停止,所有的都遍历完了还找不到指定的模板的时候就是 Template Not Found (过程类似于Python找包)。这样设计有利当然也有弊,有利是的地方是一个app可以用另一个app的模板文件,弊是有可能会找错了。所以我们使用的时候在 templates 中建立一个 app 同名的文件夹,这样就好了。这就需要把每个app中的 templates 文件夹中再建一个 app 的名称,仅和该app相关的模板放在 app/templates/app/ 目录下面。这样在使用的时候,有app作为名称的一部分,就不会混淆。
模板include
假如我们有以下模板index.html,代码:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
-
- <div>网页公共头部部分</div>
-
- <h2> 网页body部分 </h2>
-
- <div>网页公共底部部分</div>
-
- </body>
- </html>
做过web开发的同学都知道大部分网页的公共头部,公共底部部分代码每个页面都一样,那么就应该将其单独拿出做为一个html, 这样修改这部分代码时候,不需要每个页面都修改, 所以在django中我们可以这么做:
top.html
<div>网页公共头部部分</div>
bottom.html
<div>网页公共底部部分</div>
index.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
-
- {% include 'top.html' %}
-
- <h2> 网页body部分 </h2>
-
- {% include 'bottom.html' %}
-
- </body>
- </html>
我们可以使用Django模板引擎的include语法,来将单独的页面包含到当前模板页面中。有同学有疑问,那我们通过视图传递给模板的上下文,在被包含的模板中可以使用吗?可以直接使用,假如我们的视图函数如下:
- def index(request):
- return render(request, 'polls/index.html', {'a': 100, 'b': 200})
该Django视图函数,传递给模板并渲染模板。
top.html修改如下:
<div>网页公共头部部分:{{ a }}</div> # 这样使用没有任何问题
我这里有这样的一个问题,假如所有的页面都使用共同的头部top.html, 可能针对1.html 2.html 3.html所使用的头部有些样式不一样,所需top.html:
<div classs='acss'>网页公共头部部分</div>
但是对于5.html, 6.html使用的头部样式为:
<div class='bcss'>网页公共头部部分</div>
很显然,如果直接通过include方式包含公共头部,会导致一些页面显示问题。既然部分参数不一样,include允许我们传递参数给被include的模板,我们可以使用with语法,那么问题解决如下:
{{ % include 'top.html' with mycss='acss' % }}
top.html修改如下:
<div class='{{mycss}}'>网页公共头部部分</div>
被包含模板中部分参数,由我们include的时候动态指定,那么top.html就不会因为细微差别而编写多份代码了。
静态文件配置
我们自己导入的一些页面相关的包就叫做静态文件
- 在app目录中先创建static目录;
- 在static目录里面导入我们的JS、CSS、Jquery和Bootstrap等;
- 在项目settings.py中添加一些配置;
- STATIC_URL = '/static/' #这个配置就相当于下面配置的别名,如果这里的名字修改了就按照这里的名字去导入
- STATICFILES_DIRS = [
- os.path.join(BASE_DIR,"static") #E:\day68\static 找到static路径
- ]
- 导入网页相关图片、CSS、JS、Jquery等
- <link rel = "stysheet",href= "/static/index.css/">
-
- <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">