python:3.7.2
Django:2.1.7
1、创建虚拟环境
虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他python包隔离。
创建目录,命名为learning_log,并切换到这个目录下,并创建一个虚拟环境。
$ mkdir learning_log
$ cd learning_log/
learning_log$ python3 -m venv ll_env
2、激活虚拟环境并安装Django
learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ pip3 install Django
3、新建项目
在处于活动的虚拟环境的情况下(ll_env包含在括号内,以下的步骤都是在虚拟环境下),执行如下命令来新建项目:
(ll_env)learning_log$ django-admin.py startproject learning_log . # 创建项目,点号是让新项目使用合适的目录结构,不能缺少。 (ll_env)learning_log$ ls # Django新建了一个名为learning_log的目录。它还创建了一个名为manage.py的文件 learning_log ll_env manage.py (ll_env)learning_log$ ls learning_log # learning_log包含4个文件 __init__.py settings.py urls.py wsgi.py
settings.py:指定Django如何与你的系统交互以及如何管理项目。在开发项目的过程中,我们将修改其中一些设置,并添加一些设置。
urls.py:告诉Django应创建哪些网页来响应浏览器请求。
wsgi.py:帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务器网关接口 )的首字母缩写。
4、创建数据库
(ll_env)learning_log$ python3 manage.py migrate
Operations to perform:...
将修改数据库称为迁移数据库。首次执行命令migrate 时,将让Django确保数据库与项目的当前状态匹配。Django将新建一个数据库。Django指出它将创建必要的数据库表,用于存储我们将在这个项目(Synchronize unmigrated apps,同步未迁移的应用程序 )中使用的 信息,再确保数据库结构与当前代码(Applyallmigrations,应用所有的迁移 )匹配。
(ll_env)learning_log$ ls
db.sqlite3 learning_log ll_env manage.py
我们运行了命令ls ,其输出表明Django又创建了一个文件——db.sqlite3。SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,因为它让你不用太关 注数据库管理的问题。
5、查看项目
(ll_env)learning_log$ python3 manage.py runserver 0.0.0.0:405 # 允许所有IP地址访问,使用405端口 Performing system checks... System check identified no issues (0 silenced). # 检查确认正确地创建了项目 March 06, 2019 - 01:45:25 Django version 2.1.7, using settings 'learning_log.settings' # Django版本以及设置文件的名称 Starting development server at http://0.0.0.0:405/ # 访问地址和端口,如果出现端口占用,则尝试其他端口 Quit the server with CONTROL-C.
6、创建应用程序
新开另一个终端窗口,并切换到manage.py所在的目录,激活该虚拟环境,并执行命令startapp。
learning_log$ source ll_env/bin/activate (ll_env)learning_log$ python3 manage.py startapp learning_logs # 创建应用程序 (ll_env)learning_log$ ls # 新增了文件夹learning_logs db.sqlite3 learning_log learning_logs ll_env manage.py (ll_env)learning_log$ ls learning_logs/ # 最重要的文件是models.py、admin.py和views.py admin.py __init__.py migrations models.py tests.py views.py
7、定义模型
模型models.py(在learning_logs目录下面)用于定义我们要在应用程序中管理的数据。在代码层面,模型就是一个类,就像前面讨论的每个类一样,包含属性 和方法。下面是表示用户将要存储的主题的模型:
from django.db import models class Topic(models.Model): # 创建Topic主题的类 """用户学习的主题""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): # 默认应使用哪个属性来显示有关主题的信息,如果是python2.7,应调用__unicode__() """返回模型的字符串表示""" return self.text
- text属性:CharField——由字符或文本组成的数据,适用于需要存储少量的文本,如名称、标题或城市。定义CharField 属性时,必须告诉Django该在数据库中预留多少空间。在这里,我们将max_length 设置成了200(即200个字符)
- date_added 是一个DateTimeField ——记录日期和时间的数据。我们传递了实参auto_add_now=True ,每当用户创建新主题时,这都让Django将这个属性自动设置成当前日期和时间。
- __str__():默认应使用哪个属性来显示有关主题的信息。这里返回的是text中的字符串。
其他的属性可以参考:https://docs.djangoproject.com/en/1.8/ref/models/fields/ 。
8、激活模型
需要在learning_log文件夹修改settings.py文件,告诉Django哪些应用程序安装到learning_log项目中。
请将INSTALLED_APPS(这是个元组) 修改成下面这样,将前面的应用程序名称添加到这个元组中:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 我的应用程序 'learning_logs', ]
接下来,需要让Django修改数据库,使其能够存储与模型Topic 相关的信息。为此,在终端窗口中执行下面的命令:
(ll_env)learning_log$ python3 manage.py makemigrations learning_logs
Migrations for 'learning_logs': 0001_initial.py: - Create model Topic
命令makemigrations 让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型Topic 创建一个表。
下面来应用这种迁移,让Django替我们修改数据库:
(ll_env)learning_log$ python3 manage.py migrate --snip-- Running migrations: Rendering model states... DONE Applying learning_logs.0001_initial... OK # 应用迁移正常
每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:
- 修改models.py;
- 对learning_logs 调用makemigrations ;
- 让Django迁移项目。
9、Django管理网站
(1)创建超级用户:创建具备所有权限的用户。
(ll_env)learning_log$ python3 manage.py createsuperuser
(2)向管理网站注册模型:我们创建应用程序learning_logs 时,Django在models.py所在的目录中创建了一个名为admin.py的文件。为向管理网站注册Topic ,请在admin.py输入下面的代码:
from django.contrib import admin from learning_logs.models import Topic admin.site.register(Topic)
现在,使用超级用户账户访问管理网站:访问http://localhost:8000/admin/ ,并输入你刚创建的超级用户的用户名和密码,你将看到类似于下图所示的屏幕。这个网页让你能够添加和修改用户和用户组,还可以管理与刚才定义的模型Topic 相关的数据。
(3)添加主题:向管理网站注册Topic 后,我们来添加第一个主题。为此,单击Topics进入主题网页,它几乎是空的,这是因为我们还没有添加任何主题。单击Add,你将看到一个用于添加新主题的表单。在第一个方框中输入Chess ,再单击Save,这将返回到主题管理页面,其中包含刚创建的主题。
10、定义模型Entry
修改models.py中的代码:
# Create your models here. class Topic(models.Model): """用户学习的主题""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): """返回模型的字符串表示""" return self.text class Entry(models.Model): # 继承了Django基类Model """学到的有关某个主题的具体指示""" topic = models.ForeignKey(Topic,on_delete=models.CASCADE) # 外键。每个主题创建时,都给它分配了一个键(或ID). text = models.TextField() # 不需要长度限制 date_added = models.DateTimeField(auto_now_add=True) class Meta: # 用于管理模型的额外信息,在需要时使用Entries来表示多个条目。若没有,将使用Entrys来表示多个条目。 verbose_name_plural = 'entries' def __str__(self): # 只呈现text前50个字符。 """返回模型的字符串表示""" return self.text[:50] + "..."
11、迁移模型Entry
由于我们添加了一个新模型,因此需要再次迁移数据库。
将慢慢地对这个过程了如指掌:
- 修改models.py
- 执行命令python manage.py makemigrations app_name
- 再执行命令python manage.py migrate。
(ll_env)learning_log$ python3 manage.py makemigrations learning_logs Migrations for 'learning_logs': learning_logs/migrations/0002_entry.py # 生成了一个新的迁移文件0002_... - Create model Entry
(ll_env)learning_log$ python3 manage.py migrate
12、向管理网站注册Entry
我们还需要注册模型Entry 。为此,需要将admin.py修改成类似于下面这样:
from django.contrib import admin from learning_logs.models import Topic, Entry admin.site.register(Topic) admin.site.register(Entry)
返回到http://localhost:405/admin/learning_logs/ ,你将看到learning_logs下列出了Entries:
单击Entries的Add链接,或者单击Entries再选择Add entry。你将看到一个下拉列表,让你能够选择要为哪个主题创 建条目,还有一个用于输入条目的文本框。从下拉列表中选择Chess,并添加一个条目(略)。
13、Django shell
输入一些数据后,就可通过交互式终端会话以编程方式查看这些数据了。命令python manage.py shell启动一个Python解释器,可使用它来探索存储在项目数据库中的数据。
(ll_env)learning_log$ python3 manage.py shell >>> from learning_logs.models import Topic >>> Topic.objects.all() <QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]> >>> topics = Topic.objects.all() >>> for topic in topics: ... print(topic.id, topic) ... 1 Chess 2 Rock Climbing >>> t = Topic.objects.get(id=1) >>> t.text 'Chess'>>> t.date_added datetime.datetime(2019, 3, 7, 2, 14, 27, 770273, tzinfo=<UTC>) >>> t.entry_set.all() <QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry: In the opening phase of the game, it's important t...>]>
14、创建网页
使用Django创建网页的过程通常分三个阶段:定义URL、编写视图和编写模板。首先,你必须定义URL模式。URL模式描述了URL是如何设计的,让Django知道如何将浏览器请求 与网站URL匹配,以确定返回哪个网页。
每个URL都被映射到特定的视图 ——视图函数获取并处理网页所需的数据。视图函数通常调用一个模板,后者生成浏览器能够理解的网页。为明白其中的工作原理,我们来创建 学习笔记的主页。我们将定义该主页的URL、编写其视图函数并创建一个简单的模板。
(1)映射URL
用户通过在浏览器中输入URL以及单击链接来请求网页,因此我们需要确定项目需要哪些URL。主页的URL最重要,它是用户用来访问项目的基础URL。当前,基础
URL(http://localhost:8000/)返回默认的Django网站,让我们知道正确地建立了项目。我们将修改这一点,将这个基础URL映射到“学习笔记”的主页。
打开项目主文件夹learning_log中的文件urls.py,我们需要在原来的基础上包含learning_logs的URL:
from django.contrib import admin from django.conf.urls import url, include urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include('learning_logs.urls',namespace='learning_logs')), # 包含earning_logs.urls内容 ]
在文件夹learning_logs中创建另一个urls.py文件:
"""定义learning_logs的URL模式""" from django.conf.urls import url # 函数url用于创建URL映射到视图 from . import views # 当前的urls.py模块所在的文件夹中导入视图 app_name='learning_logs' # 防止出现错误:Specifying a namespace in include() without providing an app_name urlpatterns = [ # 主页 url(r'^$', views.index, name='index'), ]
url()函数接受三个实参:
- 第一个是一个正则表达式,查找找开头和末尾之间没有任何东西的URL;
- 第二个指定了要调用的视图函数(下节编写);
- 第三个实参将 这个URL模式的名称指定为index,让我们能够在代码的其他地方引用它。每当需要提供到这个主页的链接时,我们都将使用这个名称,而不编写URL。
(2)编写视图
修改learning_logs中的文件views.py文件:
from django.shortcuts import render def index(request): """学习笔记的主页""" return render(request, 'learning_logs/index.html')
URL请求与我们刚才定义的模式匹配时,Django将在文件views.py中查找函数index() ,再将请求对象传递给这个视图函数。在这里,我们不需要处理任何数据,因此这个函数只 包含调用render() 的代码。这里向函数render() 提供了两个实参:原始请求对象以及一个可用于创建网页的模板。下面来编写这个模板。
(3)编写模板
模板定义了网页的结构。模板指定了网页是什么样的,而每当网页被请求时,Django将填入相关的数据。模板让你能够访问视图提供的任何数据。我们的主页视图没有提供任何数据,因此相应的模板非常简单。
在文件夹learning_logs中新建一个文件夹,并将其命名为templates。在文件夹templates中,再新建一个文件夹,并将其命名为learning_logs。这好像有点多余(我们在文件夹 learning_logs中创建了文件夹templates,又在这个文件夹中创建了文件夹learning_logs),但建立了Django能够明确解读的结构,即便项目很大,包含很多应用程序亦如此。在最里面 的文件夹learning_logs中,新建一个文件,并将其命名为index.html,再在这个文件中编写如下代码:
<p>Learning Log</p> <p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
现在,如果你请求这个项目的基础URL——http://localhost:8000/,将看到刚才创建的网页,而不是默认的Django网页。Django接受请求的URL,发现该URL与模式r'^$' 匹配,因此 调用函数views.index() ,这将使用index.html包含的模板来渲染网页,结果如下图所示。
15、创建其他网页
我们将创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们 都将指定URL模式,编写一个视图函数,并编写一个模板。但这样做之前,我们先创建一个父模板,项目中的其他模板都将继承它。
15.1 模板继承
创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通
用元素。这种方法能让你专注于开发每个网页的独特方面,还能让修改项目的整体外观容易得多。
(1)父模板
我们首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件包含所有页面都有的元素;其他的模板都继承base.html。当前,所有页面都包含的元素 只有顶端的标题。我们将在每个页面中包含这个模板,因此我们将这个标题设置为到主页的链接:
<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> </p> {% block content %}{% endblock content %}
这个文件的第一部分创建一个包含项目名的段落,该段落也是一个到主页的链接。为创建链接,我们使用了一个模板标签 ,它是用大括号和百分号({% %} )表示的。模板标签是一小段代码,生成要在网页中显示的信息。在这个实例中,模板标签{% url 'learning_logs:index' %}生成一个URL,该URL与learning_logs/urls.py中定义的名 为index 的URL模式匹配。在这个示例中,learning_logs 是一个命名空间 ,而index 是该命名空间中一个名称独特的URL模式。
我们插入了一对块标签。这个块名为content ,是一个占位符,其中包含的信息将由子模板指定。子模板并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。
在Python代码中,我们几乎总是缩进四个空格。相比于Python文件,模板文件的缩进层级更多,因此每个层级通常只缩进两个空格。
(2)子模块
现在需要重新编写index.html,使其继承base.html,如下所示:
{% extends "learning_logs/base.html" %} {% block content %} <p>Learning Log</p> <p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p> {% endblock content %}
如果将这些代码与原来的index.html进行比较,可发现我们将标题LearningLog替换成了从父模板那里继承的代码。子模板的第一行必须包含标签{% extends %},让 Django知道它继承了哪个父模板。文件base.html位于文件夹learning_logs中,因此父模板路径中包含learning_logs。这行代码导入模板base.html的所有内容,让index.html能够指定要 在content 块预留的空间中添加的内容。
我们插入了一个名为content的{% block %}标签,以定义content块。不是从父模板继承的内容都包含在content块中,在这里是一个描述项目“学习笔记”的 段落。我们使用标签{% endblock content %}指出了内容定义的结束位置。
模板继承的优点开始显现出来了:在子模板中,只需包含当前网页特有的内容。这不仅简化了每个模板,还使得网站修改起来容易得多。要修改很多网页都包含的元素,只需在父模板中修改该元素,你所做的修改将传导到继承该父模板的每个页面。在包含数十乃至数百个网页的项目中,这种结构使得网站改进起来容易而且快捷得多。
在大型项目中,通常有一个用于整个网站的父模板——base.html,且网站的每个主要部分都有一个父模板。每个部分的父模板都继承base.html,而网站的每个网 页都继承相应部分的父模板。这让你能够轻松地修改整个网站的外观、网站任何一部分的外观以及任何一个网页的外观。这种配置提供了一种效率极高的工作方式, 让你乐意不断地去改进网站。
15.2 显示所有主题的页面
(1)URL模式:首先,我们来定义显示所有主题的页面的URL。通常,使用一个简单的URL片段来指出网页显示的信息;我们将使用单词topics,因此URL http://localhost:8000/topics/将返回显示所有 主题的页面。下面演示了该如何修改learning_logs/urls.py:
"""定义learning_logs的URL模式""" from django.conf.urls import url from . import views app_name='learning_logs' 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中添加的代码如下:
from django.shortcuts import render from .models import Topic def index(request): """学习笔记的主页""" return render(request, 'learning_logs/index.html') def topics(request): """显示所有的主题""" topics = Topic.objects.order_by('date_added') context = {'topics': topics} return render(request, 'learning_logs/topics.html', context)
我们首先导入了与所需数据相关联的模型。
函数topics() 包含一个形参:Django从服务器那里收到的request 对象。我们查询数据库——请求提供Topic 对象,并按属性date_added 对它们进行排序。我们将返回的查询集存储在topics 中。
我们定义了一个将要发送给模板的上下文。上下文是一个字典,其中的键是我们将在模板中用来访问数据的名称,而值是我们要发送给模板的数据。在这里,只有一个 键—值对,它包含我们将在网页中显示的一组主题。创建使用数据的网页时,除对象request 和模板的路径外,我们还将变量context 传递给render() 。
(3)模板:显示所有主题的页面的模板接受字典context ,以便能够使用topics() 提供的数据。请创建一个文件,将其命名为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 %}
就像模板index.html一样,我们首先使用标签{% extends %}来继承base.html,再开始定义content块。这个网页的主体是一个项目列表,其中列出了用户输入的主题。在标准 HTML中,项目列表被称为无序列表,用标签<ul></ul> 表示。
我们使用了一个相当于for 循环的模板标签,它遍历字典context 中的列表topics 。模板中使用的代码与Python代码存在一些重要差别:Python使用缩进来指出哪些 代码行是for循环的组成部分,而在模板中,每个for循环都必须使用{% endfor %}标签来显式地指出其结束位置。因此在模板中,循环类似于下面这样:
{% for item in list %} do something with each item {% endfor %}
在循环中,我们要将每个主题转换为一个项目列表项。要在模板中打印变量,需要将变量名用双花括号括起来。每次循环时,代码{{ topic }}都被替换为topic的当 前值。这些花括号不会出现在网页中,它们只是用于告诉Django我们使用了一个模板变量。HTML标签<li></li> 表示一个项目列表项,在标签对<ul></ul> 内部,位于标 签<li> 和</li> 之间的内容都是一个项目列表项。
我们使用了模板标签{% empty %},它告诉Django在列表topics为空时该怎么办:这里是打印一条消息,告诉用户还没有添加任何主题。最后两行分别结束for循 环和项目列表。
现在需要修改父模板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模式匹配。
现在如果你刷新浏览器中的主页,将看到链接Topics。单击这个链接,将看到类似于图18-4所示的网页。
15.3 显示特定主题的页面
1、URL模式
显示特定主题的页面的URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id 属性来指出请求的是哪个主题。例如,如果用户要查看主题Chess(其id 为1)的详细页面,URL将为http://localhost:8000/topics/1/。下面是与这个URL匹配的模式,它包含在learning_logs/urls.py中:
"""定义learning_logs的URL模式""" from django.conf.urls import url from . import views app_name='learning_logs' urlpatterns = [ # 主页 url(r'^$', views.index, name='index'), # 显示所有的主题 url(r'^topics/$', views.topics, name='topics'), # 制定主题的详细页面 url(r'^topics/(?P<topic_id>d+)/$', views.topic, name='topic') ]
r'^topics/(?P<topic_id>d+)/$' 。
r 让Django将这个字符串视为原始字符串,并指出正则表达式包含在引号内。
(/(?P<topic_id>d+)/ )与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为topic_id 的实参中。这部分表达式两边的括号捕获URL中的 值;?P<topic_id> 将匹配的值存储到topic_id 中;而表达式d+ 与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。
发现URL与这个模式匹配时,Django将调用视图函数topic() ,并将存储在topic_id 中的值作为实参传递给它。在这个函数中,我们将使用topic_id 的值来获取相应的主 题。
2、视图
函数topic() 需要从数据库中获取指定的主题以及与之相关联的所有条目,如下所示:
from django.shortcuts import render from .models import Topic def index(request): """学习笔记的主页""" return render(request, 'learning_logs/index.html') def topics(request): """显示所有的主题""" topics = Topic.objects.order_by('date_added') context = {'topics': topics} return render(request, 'learning_logs/topics.html', context) 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)
这是第一个除request 对象外还包含另一个形参的视图函数。这个函数接受正则表达式(?P<topic_id>d+) 捕获的值,并将其存储到topic_id 中。
我 们使用get() 来获取指定的主题,就像前面在Django shell中所做的那样。
我们获取与该主题相关联的条目,并将它们按date_added 排序:date_added 前面的减号 指定按降序排列,即先显示最近的条目。我们将主题和条目都存储在字典context 中,再将这个字典发送给模板topic.html。
在自己的项目中编写这样的查询时,先在Django shell中进行尝试大有裨益。相比于编写视 图和模板,再在浏览器中检查结果,在shell中执行代码可更快地获得反馈。
(3)模板
这个模板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 %}
像这个项目的其他页面一样,这里也继承了base.html。接下来,我们显示当前的主题,它存储在模板变量{{ topic }}中。为什么可以使用变量topic呢?因为它包含在字典context 中。接下来,我们开始定义一个显示每个条目的项目列表,并像前面显示所有主题一样遍历条目。
每个项目列表项都将列出两项信息:条目的时间戳和完整的文本。为列出时间戳,我们显示属性date_added 的值。在Django模板中,竖线(| )表示模板过滤器—— 对模板变量的值进行修改的函数。过滤器date: 'M d, Y H:i'以这样的格式显示时间戳:January1,2015 23:00。接下来的一行显示text的完整值,而不仅仅是entry的前 50个字符。过滤器linebreaks将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。我们使用模板标签{% empty %}打 印一条消息,告诉用户当前主题还没有条目。
(4) 将显示所有主题的页面中的每个主题都设置为链接
在浏览器中查看显示特定主题的页面前,我们需要修改模板topics.html,让每个主题都链接到相应的网页,如下所示:
{% extends "learning_logs/base.html" %} {% block content %} <p>Topics</p> <ul> {% 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 %} </ul> {% endblock content %}
我们使用模板标签url 根据learning_logs中名为topic 的URL模式来生成合适的链接。这个URL模式要求提供实参topic_id ,因此我们在模板标签url 中添加了属性topic.id 。现在,主题列表中的每个主题都是一个链接,链接到显示相应主题的页面,如http://localhost:8000/topics/1/。
如果你刷新显示所有主题的页面,再单击其中的一个主题,将看到类似于图18-5所示的页面。
参考资料:
1、python编程,从入门到实践