目录
18.4 创建其他网页
18.4.1 模板继承
1. 父模板
base.html
注意
2. 子模板
index.html
注意
18.4.2 显示所有主题的页面
1. URL模式
urls.py
2. 视图
views.py
3. 模板
topics.html
18.4.3 显示特定主题的页面
1. URL模式
urls.py
2. 视图
views.py
往期快速传送门👆(在文章最后):
感谢大家的支持!欢迎订阅收藏!专栏将持续更新!
18.4 创建其他网页
制定创建网页的流程后,可以开始扩充“学习笔记”项目了。我们将创建两个显示数据的网 页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定 URL模式,编写一个视图函数,并编写一个模板。但这样做之前,我们先创建一个父模板,项目 中的其他模板都将继承它。
18.4.1 模板继承
创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用 元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。这 种方法能让你专注于开发每个网页的独特方面,还能让修改项目的整体外观容易得多。
1. 父模板
我们首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件 包含所有页面都有的元素;其他的模板都继承base.html。当前,所有页面都包含的元素只有顶端 的标题。我们将在每个页面中包含这个模板,因此我们将这个标题设置为到主页的链接:
base.html
<p>
1 <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
2 {% block content %}{% endblock content %}
这个文件的第一部分创建一个包含项目名的段落,该段落也是一个到主页的链接。为创建链 接,我们使用了一个模板标签,它是用大括号和百分号({% %})表示的。模板标签是一小段代 码,生成要在网页中显示的信息。在这个实例中,模板标签{% url 'learning_logs:index' %}生成一个URL,该URL与learning_logs/urls.py中定义的名为index的URL模式匹配(见)。在这 个示例中,learning_logs是一个命名空间,而index是该命名空间中一个名称独特的URL模式。 在简单的HTML页面中,链接是使用锚标签定义的:
<a href="link_url">link text</a>
让模板标签来生成URL,可让链接保持最新容易得多。要修改项目中的URL,只需修改urls.py 中的URL模式,这样网页被请求时,Django将自动插入修改后的URL。在我们的项目中,每个网 页都将继承base.html,因此从现在开始,每个网页都包含到主页的链接。
在2处,我们插入了一对块标签。这个块名为content,是一个占位符,其中包含的信息将 由子模板指定。
子模板并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间, 而子模板可根据需要定义相应数量的块。
注意
在Python代码中,我们几乎总是缩进四个空格。相比于Python文件,模板文件的缩进层级 更多,因此每个层级通常只缩进两个空格。
2. 子模板
现在需要重新编写index.html,使其继承base.html,如下所示:
index.html
1 {% extends "learning_logs/base.html" %}
2 {% block content %}<p>Learning Log helps you keep track of your learning, for any topic you'relearning about.</p>
3 {% endblock content %}
如果将这些代码与原来的index.html进行比较,可发现我们将标题Learning Log替换成了从父 模板那里继承的代码(见1)。子模板的第一行必须包含标签{% extends %},让Django知道它继 承了哪个父模板。文件base.html位于文件夹learning_logs中,因此父模板路径中包含learning_logs。 这行代码导入模板base.html的所有内容,让index.html能够指定要在content块预留的空间中添加 的内容。
在2处,我们插入了一个名为content的{% block %}标签,以定义content块。不是从父模板 继承的内容都包含在content块中,在这里是一个描述项目“学习笔记”的段落。在处,我们 使用标签{% endblock content %}指出了内容定义的结束位置。
模板继承的优点开始显现出来了:在子模板中,只需包含当前网页特有的内容。这不仅简化 了每个模板,还使得网站修改起来容易得多。要修改很多网页都包含的元素,只需在父模板中修 改该元素,你所做的修改将传导到继承该父模板的每个页面。在包含数十乃至数百个网页的项目中,这种结构使得网站改进起来容易而且快捷得多。
注意
在大型项目中,通常有一个用于整个网站的父模板——base.html,且网站的每个主要部 分都有一个父模板。每个部分的父模板都继承base.html,而网站的每个网页都继承相应 部分的父模板。这让你能够轻松地修改整个网站的外观、网站任何一部分的外观以及任 何一个网页的外观。这种配置提供了一种效率极高的工作方式,让你乐意不断地去改进 网站。
18.4.2 显示所有主题的页面
有了高效的网页创建方法,就能专注于另外两个网页了:显示全部主题的网页以及显示特定 主题中条目的网页。所有主题页面显示用户创建的所有主题,它是第一个需要使用数据的网页。
1. URL模式
首先,我们来定义显示所有主题的页面的URL。通常,使用一个简单的URL片段来指出网页 显示的信息;我们将使用单词topics,因此URL http://localhost:8000/topics/将返回显示所有主题的 页面。下面演示了该如何修改learning_logs/urls.py:
urls.py
"""为learning_logs定义URL模式"""
--snip--
urlpatterns = [# 主页url(r'^$', views.index, name='index'),# 显示所有的主题
url(r'^topics/$', views.topics, name='topics'),
]
我们只是在用于主页URL的正则表达式中添加了topics/(见)。Django检查请求的URL时, 这个模式与这样的URL匹配:基础URL后面跟着topics。可以在末尾包含斜杠,也可以省略它, 但单词topics后面不能有任何东西,否则就与该模式不匹配。其URL与该模式匹配的请求都将交 给views.py中的函数topics()进行处理。
2. 视图
函数topics()需要从数据库中获取一些数据,并将其发送给模板。我们需要在views.py中添 加的代码如下:
views.py
from django.shortcuts import render
1 from .models import Topic
def index(request):--snip--
2 def topics(request):"""显示所有的主题"""
3 topics = Topic.objects.order_by('date_added')
4 context = {'topics': topics}
5 return render(request, 'learning_logs/topics.html', context)
我们首先导入了与所需数据相关联的模型(见1)。函数topics()包含一个形参:Django从服 务器那里收到的request对象(见2)。在3处,我们查询数据库——请求提供Topic对象,并按属 性date_added对它们进行排序。我们将返回的查询集存储在topics中。
在4处,我们定义了一个将要发送给模板的上下文。上下文是一个字典,其中的键是我们将 在模板中用来访问数据的名称,而值是我们要发送给模板的数据。在这里,只有一个键—值对, 它包含我们将在网页中显示的一组主题。创建使用数据的网页时,除对象request和模板的路径 外,我们还将变量context传递给render()(见5)。
3. 模板
显示所有主题的页面的模板接受字典context,以便能够使用topics()提供的数据。请创建一 个文件,将其命名为topics.html,并存储到index.html所在的目录中。下面演示了如何在这个模板 中显示主题:
topics.html
{% extends "learning_logs/base.html" %}
{% block content %}<p>Topics</p>
1 <ul>
2 {% for topic in topics %}
3 <li>{{ topic }}</li>
4 {% empty %}<li>No topics have been added yet.</li>
5 {% endfor %}
6 </ul>
{% endblock content %}
就像模板index.html一样,我们首先使用标签{% extends %}来继承base.html,再开始定义 content块。这个网页的主体是一个项目列表,其中列出了用户输入的主题。在标准HTML中,项 目列表被称为无序列表,用标签
表示。包含所有主题的项目列表始于1处。 在2处,我们使用了一个相当于for循环的模板标签,它遍历字典context中的列表topics。 模板中使用的代码与Python代码存在一些重要差别:Python使用缩进来指出哪些代码行是for循环 的组成部分,而在模板中,每个for循环都必须使用{% endfor %}标签来显式地指出其结束位置。因此在模板中,循环类似于下面这样:
{% for item in list %}do something with each item
{% endfor %}
<p>
1 <a href="{% url 'learning_logs:index' %}">Learning Log</a> -
2 <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>
{% block content %}{% endblock content %}
我们在到主页的链接后面添加了一个连字符(见1),然后添加了一个到显示所有主题的页 面的链接——使用的也是模板标签url(见2)。这一行让Django生成一个链接,它与learning_logs/ urls.py中名为topics的URL模式匹配。
现在如果你刷新浏览器中的主页,将看到链接Topics。单击这个链接,将看到类似于图18-4 所示的网页.
18.4.3 显示特定主题的页面
接下来,我们需要创建一个专注于特定主题的页面——显示该主题的名称及该主题的所有条 目。同样,我们将定义一个新的URL模式,编写一个视图并创建一个模板。我们还将修改显示所 有主题的网页,让每个项目列表项都是一个链接,单击它将显示相应主题的所有条目。
1. URL模式
显示特定主题的页面的URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id 属性来指出请求的是哪个主题。例如,如果用户要查看主题Chess(其id为1)的详细页面,URL 将为http://localhost:8000/topics/1/。下面是与这个URL匹配的模式,它包含在learning_logs/urls.py中:
urls.py
--snip--
urlpatterns = [--snip--# 特定主题的详细页面url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
]
我们来详细研究这个URL模式中的正则表达式——r'^topics/(?P\d+)/$'。r让 Django将这个字符串视为原始字符串,并指出正则表达式包含在引号内。这个表达式的第二部分 (/(?P\d+)/)与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为topic_id 的实参中。这部分表达式两边的括号捕获URL中的值;?P将匹配的值存储到topic_id 中;而表达式\d+与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。 发现URL与这个模式匹配时,Django将调用视图函数topic(),并将存储在topic_id中的值作 为实参传递给它。在这个函数中,我们将使用topic_id的值来获取相应的主题。
2. 视图
函数topic()需要从数据库中获取指定的主题以及与之相关联的所有条目,如下所示:
views.py
--snip--
1 def topic(request, topic_id):"""显示单个主题及其所有的条目"""
2 topic = Topic.objects.get(id=topic_id)
3 entries = topic.entry_set.order_by('-date_added')
4 context = {'topic': topic, 'entries': entries}
5 return render(request, 'learning_logs/topic.html', context)
关于“Python”的核心知识点整理大全37-CSDN博客
关于“Python”的核心知识点整理大全25-CSDN博客
关于“Python”的核心知识点整理大全12-CSDN博客