参考书籍:《Python编程从入门到实践》—Eric Matthes
我们将创建两个显示数据的网 页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定 URL模式,编写一个视图函数,并编写一个模板
模板继承
创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用 元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。所以我们先创建一个父模板。
父模板
我们首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件 包含所有页面都有的元素;其他的模板都继承base.html。当前,所有页面都包含的元素只有顶端 的标题。我们将在每个页面中包含这个模板,因此我们将这个标题设置为到主页的链接
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
{% block content %}{% endblock content %}
- 模板标签(用{% %}表示)生成一个URL,该URL与learning_logs/urls.py中定义的名为index的URL模式匹配。
- 在最后一行我们插入了一对块标签,名为content,是一个占位符,其中包含的消息由子模版指定。
子模版
重新编写index.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 %}
- 将标题Learning Log替换成了从父模板那里继承的代码。
- content的{% block %}是一个描述项目"学习笔记"的段落。
显示所有主题的页面
URL模式
定义URL https://localhost:8000/topics返回显示所有主题的页面。
在learning_logs/urls.py中添加
#显示所有的主题
url(r'^topics/$',views.topics,name='topics'),
视图
在views.py中添加库函数
from .models import Topic
再添加
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added')
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)
topics = Topic.objects.order_by('date_added')
请求Topic对象,并按属性date_added对它们进行排序- 最后,我们定义了一个将要发送给模板的上下文。上下文是一个字典,其中的键是我们在模板中用来访问数据的名称,而值是我们要发送给模板的数据。
模板
显示所有主题的页面的模板接受字典context。在index.html所在的目录下新建文件topics.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>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{% endblock content %}
修改父模板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 %}
- '-'是一个连字符,然后添加了一个到显示所有主题的页面的链接——使用的也是模板标签url。这让Django生成一个链接,它与learning_logs/urls.py中名为topics的URL模式匹配。
注意!!!如果此时出现learning_logs' is not a registered namespace
的错误,在learning_logs/urls.py末尾中添加:app_name='learning_logs'
淦,之前一直报错原来是把Topic模型里面的date_added打成data了。好不容易改了之后又出现了OperationalError at/admin/learning_logs/topic/add table learning_logs_topic has no column named text
的问题,原因是更改了models.py文件里面的主题之后没有迁移数据库,一定要记得更改了models.py的文件后要执行python manage.py makemigration learning_logs
python manage.py migrate
这两步命令!!!
主页图:
Topic:
显示特定主题的页面
我们还需要一个显示具体主题的页面。所以需要定义一个新的URL模式,编写一个视图和创建一个模板。
URL模式
#在learning_logs/urls.py中添加
#特定主题的详细页面
url(r'^topics/(?P<topic_id>\d+)/$',views.topic,name='topic'),
这同样包含了一个正则表达式。r让Django将这个字符串当作原始字符串,并指出正则表达式在引号内。(/(?P<topic_id>\d+)/)
与包含在两个斜杠内的整数匹配,并将整数存储在topic_id中。这部分表达式两边的括号捕获URL的值,表达式\d+
与两个斜杠内的任何数字都匹配。
如果发现URL与这个模式匹配,Django就会调用视图函数topic(),并将topic_id中的值作为值传递给它。
视图
在views.py中添加
def topic(request,topic_id):
"""显示单个主题及其所有的条目"""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic':topic,'entries':entries}
return render(request,'learning_logs/topic.html',context)
- 函数接受正则表达式
(?P<topic_id>\d+)
捕获的值 - 使用get获取指定的主题
-date_added
按降序排序,即先显示最近的条目- 然后将主题和条目都存储在context字典中,最后发送给模板topic.html
模板
在index.html所在目录下添加topic.html文件
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>Topic:{{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%}
- 每个列表项目都将列出两项信息:条目的时间戳和完整的文本。为了列出时间戳,显示出属性date_added的值。在Django中,竖线’|'表示模板过滤器——对模板变量的值进行修改的函数。在这里过滤器
date:'M d, Y H:i'
按照月 日 年 时分的格式显示时间。 - 下一行的过滤器linebreaks将包含换行符的长条目转换为浏览器就能理解的格式。
将显示所有主题的每个主题都设置为链接
修改topics.html
{% for topic in topics %}
<li>
<a href="{%url 'learning_logs:topic' topic.id%}">{{ topic }}</a>
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
使用learnings_logs中名为topic的URL模式来生成合适的链接。这个URL模式要求提供实参topic_id,因此我们在模板标签url中添加了属性topic.id。
这里出现了一个小插曲,出现了TemplateDoesNotExist
的报错,在这里需要看html是否正确放在了templates/learning_logs的目录下。
效果图: