创建其他网页
1. 模板继承
创建网站时,几乎都有一些网页都将包含的元素,在这种情况下,可以编写一个包含通用元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。
Ⅰ、父模板:
我们首先来创建一个名为base.html
的模板,并将其存储在index.html
所在的目录中。这个页面包含所有页面都有的元素,其他模板都继承它:
<p>
<a href={% url 'learning_logs:index' %}>Learning Log</a>
</p>
{% block content %}{% endblock content%}
这个文件的第一部分创建一个包含项目名的段落,该段落也是一个到主页的链接,为创建链接,我们使用了一个模板标签
,它是用大括号和百分号
( {% %} )
表示的。子模板并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块
注:在python代码中,我们几乎总是缩进四个空格,相比于python文件,模块文件的缩进层级更多,因此每个层级通常只缩进两个空格!!
Ⅱ、子模板:
现在需要重新编写index.html
,使其继承base.html
,执行以下代码:
{% extends "learning_logs/base.html" %}
{% block content %}
# <p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
{% endblock content%}
子模板第一行必须包含标签{% extends %}
,让Django知道它继承了哪个父模板。在这里模板继承的优点就显现出来了:在子模板中,只需包含当前网页特有的内容,这不仅简化了每个模板,还使得网站修改起来容易很多,要修改很多网页都包含的元素,只需在父模板中修改该元素,你所做的修改将传导到继承该父模板得每个页面。
在大型项目中,通常有一个用于整个网站的父模板------base.html,且网站的每个主要部分都有一个父模板,每个部分的父模板都继承base.html,而网站的每个网页都继承相应部分的父模板。
2.显示所有主题的页面
Ⅰ、URL模式:
首先,我们来定义显示所有主题的页面的URL,通常使用一个简单的URL片段来指出网页显示的信息,在这里我们将使用单词topics,因此URL http://localhost:8000/topics/
将返回显示所有主题的页面,下面我们来修改learning_logs/urls.py
:
# """为learning_logs定义URL模式"""
# --snip--
# urlpatterns = [
# 主页
# url(r'^$', views.index, name = 'index'),
# 显示所有的主题
url(r'^topics/$', views.topics, name = 'topics'),
]
Ⅱ、视图
函数topics()
需要从数据库中获取一些数据,并将其发送给模板,我们需要在views.py
中添加以下代码:
# from django.shortcuts import render
from .models import Topic
# defindex(request):
# --snip--
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html',context)
Ⅲ、模板
我们来创建一个文件,将其命名为topics.html
,并存储到index.html
所在的目录中,下面演示了如何在这个模板中显示主题:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>{{ topic }}</li>
<% empty %>
<li>NO topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content%}
代码第5行的for循环模板标签,它遍历字典context中的列表topics,模板中使用的代码与python代码存在一些重要差别:python使用缩进来指出哪些代码行是for循环的组成部分,而在模板中,每个for循环都必须使用{% endfor %}
标签来显式地指出其结束位置。代码的第7行我们使用了模板标签<% empty %>
,它告诉Django在列表topics为空时该怎么办:这里是打印一条消息,来告诉用户还没有添加任何主题
现在需要修改父模板base.html
,使其包含到显示所有主题的页面的链接:
<p>
# <a href={% url 'learning_logs:index' %}>Learning Log</a>
<a href={% url 'learning_logs:topics' %}>Topics</a>
</p>
# {% block content %}{% endblock content%}
现在如果刷新浏览器的主页,你将看到链接Topics,单击这个链接,你将看到自己之前添加的主题。
3.显示特定的主题页面
Ⅰ、URL模式
显示特定的主题的页面URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id属性来指出请求的是哪个主题,打开learning_logs/urls.py
,执行以下代码:
# --snip--
# urlpatterns = [
# --snip--
# 特定主题的详细页面
url(r'^topics/(?p<topic_id>\d+)/$', views.topic, name = 'topic'),
]
Ⅱ、视图
函数topic()
需要从数据库中获取指定的主题以及与之相关联的所有条目,打开views.py
,执行以下代码:
# --snip--
def topics(request,topic_id):
"""显示单个主题及其所有的条目"""
topics = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topics': topics, 'entries':entries}
return render(request, 'learning_logs/topics.html',context)
在代码的第四行('-date_added')
表示我们获取的与该主题相关的条目将按date_added
降序排序,即先显示最近的条目。代码第四五行被称为查询,因为它们向数据库查询特定的信息,在自己的项目中编写这样的查询时,先在Django shell
中进行尝试将大有脾益。
Ⅲ、模板
这个模板需要显示主题的名称和条目的内容,如果当前主题不包含任何条目,我们还需向用户指出这一点,打开topic.html
,并执行以下代码:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics:{{ topic }}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
<% empty %>
<li>There are no entries for this topic yet.</li>
{% endfor %}
</ul>
{% endblock content%}
每个项目列表项都将列出两项信息:条目的时间戳和完整的文本。在Django模板中,竖线(|)
表示模板过滤器------对模板变量的值进行修改的函数。过滤器linebreaks
将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。
Ⅳ、将显示所有主题的页面中的每个主题都设置为链接
修改模板topic.html
:
# --snip--
# {% for topic in topics %}
<li>
<a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
</li>
# <% empty %>
# --snip--
现在,主题列表中的每个主题都是一个链接,链接到显示相应主题的页面,例如:http://localhost:8000/topics/2/