---恢复内容开始---
昨天敲得忘记保存了。。。然后自动恢复了一些,有点难受。。。就当巩固一遍吧。
18.1 建立项目
18.1.1 制定规范
编写一个名为“学习笔记”的Web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,就可以创建新主题、添加新条目以及阅读既有的条目。
18.1.2 建立虚拟环境
要使用Django,首先需要建立一个虚拟工作环境。虚拟工作环境是系统的一个位置,你可以再其中安装包,并将其与其他Python包隔离。
为项目新建一个目录,将其命名为learning_log,再在终端中切换到这个目录,并创建一个虚拟环境。
18.1.4 激活虚拟环境
Windows系统,使用命令11_envScriptsactivate(不包含source)
要停止使用虚拟环境,可执行命令deactivate
18.1.5 安装Django
18.1.6 在Django中创建项目
在仍然处于活动的虚拟环境的情况下(11_env包含在括号内),执行命令新建一个项目:
这个命令末尾的句点让新项目使用合适的目录结构,千万不能忘了这个句点,否则部署应用程序时,将遭遇一些配置问题。
目录learning_log包含4个文件,其中最重要的是settings.py、urls.py和wsgi.py。文件settings.py指定Django如何与你的系统交互以及如何管理项目。在开发项目的过程中,我们将修改其中一些设置,并添加一些设置。文件urls.py告诉Django应创建哪些网页来响应浏览器请求。文件wsgi.py帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务器网关接口)
18.1.7 创建数据库
为给项目“学习笔记”创建数据库,请在处于活跃虚拟环境中的情况下执行下面的命令:
python manage.py migrate
我们将修改数据库称为迁移数据库,首次执行命令migrate时,将让Django确保数据库与项目的当前状态匹配。在使用SQLite的新项目中首次执行这个命令时,Django将新建一个数据库。
18.1.8 查看项目
下面核实Django是否正确地创建了项目。为此,可执行命令runserver:
python manage.py runserver
Django通过检查确认正确地创建了项目;指出了使用的Django版本以及当前使用的设置文件的名称;它指出了项目的URL。
Django启动一个服务器,让你能够查看系统中的项目,了解它们的工作情况。
现打开一款Web浏览器,并输入URL:http://localhost:8000/;如果不管用,请输入http://127.0.0.1:8000/
18.2 创建应用程序
Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。我们暂时只创建一个应用程序,它将完成项目的大部分工作。
当前,在前面打开的终端窗口中应该还运行着runserver。请再打开一个终端窗口(或标签页),并切换到manage.py所在的目录。激活虚拟环境,再执行命令startapp:
python manage.py startapp learning_logs
命令startapp appname让Django建立创建应用程序所需的基础设施。项目目录增加一个文件夹learning_logs。打开这个文件夹,其中最重要的文件是models.py、admin.py和views.py。我们将使用models.py来定义我们要在应用程序中管理的数据。
18.2.1 定义模型
打开文件models.py,下面表示用户将要存储的主题的模型:
from django.db import models # 定义了一个名为Topic的类,它继承了Model—Django中一个定义了模型基本功能的类 # 属性text是一个CharField—由字符或文本组成的数据。需要存储少量的文本,如名称、标题或城市时,可以使用 # date_added是一个DateTimeField—记录日期和时间的数据。 class Topic(models.Model): """用户学习主题""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): """返回模型的字符串表示""" return self.text
注意,要或许可在模型中使用的各种字段,请参阅Django Model Field Reference(Django模型字段参考),其网址为https://docs.djangoproject.com/en/1.8/ref/models/fields/
18.2.2 激活模型
要使用模型,必须让Django将应用程序包含到项目中。为此,打开dettings.py,你将看到下面的片段,这是一个元组,告诉Django是由哪些元组组成的。添加learning_logs。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # My apps 'learning_logs', ]
接下来,需要让Django修改数据库,使其能够存储与模型Topic相关的信息。为此在终端窗口执行命令:
python manage.py makemigrations learning_logs
输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型Topic创建一个表。
下面来应用这种迁移。让Django替我们修改数据库:
python manage.py migrate
每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。
18.2.3 Django管理网站
为应用程序定义模型,Django提供的管理网站让你能够轻松地处理模型。网站的管理员可使用管理网站,但普通用户不能使用。
1、创建超级用户
python manage.py createsuperuser
昨天的数据丢失啦,只能重新创建一个管理员了,密码需要数字和字母的结合,email地址可为空。
2、向管理网站注册模型
Django自动在管理网站中添加了一些模型,如User和Group,但对于我们创建的模型,必须手工注册。
打开admin.py文件,为向管理网站注册Topic,请输入以下代码:
from django.contrib import admin from learning_logs.models import Topic admin.site.register(Topic)
现在,使用超级用户账户访问管理网站:http://localhost:8000/admin,这个网页让你能够添加和修改用户和用户组,还可以管理与刚才定义的模型Topic相关的数据。
3、添加主题
18.2.4 定义模型Entry
要记录学到的国际象棋和攀岩知识,需要为用户可在学习笔记中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一主题。
下面是模型Entry的代码:
class Entry(models.Model): """学到的有关某个主题的具体知识""" # ForeignKey外键,引用了数据库中的另一条记录; # 每个主题创建时,都给它分配了一个键(或ID)。 # 嵌套Meta类,Meta存储用于管理模型的额外信息。 topic = models.ForeignKey(Topic,on_delete=models.CASCADE) text = models.TextField() date_added = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = 'entries' def __str__(self): return self.text[:50]+"..."
18.2.5 迁移模型Entry
由于我们添加了一个新模型,因此需要再次迁移数据库。你将慢慢地对这个过程了如指掌:修改models.py,执行命令python manage.py makemigrations app_name,再执行命令python manage.py migrate。
下面来迁移数据库并查看输出:
18.2.6 向管理网站注册Entry
from django.contrib import admin from learning_logs.models import Topic,Entry admin.site.register(Topic) admin.site.register(Entry)
返回到http://localhost:8000/admin/(注意需要重新开启服务器)
下面添加条目:
18.2.7 Django shell
输入一些数据,就可以通过交互终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell,是测试项目和排除其他故障的理想之地。
返回一个列表,称为查询集(queryset)
下面演示了如何查看分配给每个主题对象的ID:
知道对象的ID后,就可获取该对象并查看其任何属性。下面来看看主题Chess的属性text和date_added的值:
我们还可以查看与主题相关联的条目。前面我们给模型Entry定义了属性topic,这是一个ForeignKey,将条目与主题关联起来。利用这种关联,Django能够获取与特定主题相关联的所有条目:
为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set。
注意,每次修改模型后,你都需要重启shell,这样才能看到修改的效果。如果想要退出shell会话,Windows系统可以按ctrl+Z,再按回车键。
p369 18-2简短的条目,使得50字以内不显示省略号。
class Meta: verbose_name_plural = 'entries' def __str__(self): if (len(self.text))>50: return self.text[:50]+"..." else: return self.text
18.3 创建网页:学习笔记主页
使用Django创建网页的过程通常分三个阶段:定义URL、编写视图和编写模块。首先,你必须定义URL模式。URL模式描述了URL是如何设计的,让Django知道如何将浏览器请求于网站URL匹配,以确定返回哪个网页。
每个URL都被映射到特定的视图——视图函数获取并处理网页所需的数据。视图通常调用一个模板,后者生成浏览器能够理解的网页。
18.3.1 映射URL
当前,基础URL(http://localhost:8000/)返回默认的Django网站,让我们知道正确地建立了项目。我们将修改这一点,将这个基础URL映射带“学习笔记”主页。
打开项目主文件夹learning_log中的文件urls.py:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ]
前两行导入为项目和管理网站URL的函数和模块。这个文件的主题定义了变量urlpatterns。在这个针对整个项目的urls.py文件中,变量urlpatterns包含项目中的应用程序的URL。我们需要包含learning_logs的URL:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'',include('learning_logs.urls',namespace='learning_logs')), ]
添加了一行代码,让我们能够将learning_logs的URL同项目中的其他URL区分开来,这在项目开始扩展时很有帮助。
默认的urls.py包含在文件夹learning_log中,现在我们需要在文件夹learning_logs中创建另一个urls.py文件:
"""定义learning_logs的URL模式""" from django.conf.urls import url from .import views urlpatterns = [ # 主页 url(r'^$',views.index,name='index') ]
实际的URL模式是一个对函数url()的调用,这个函数接受三个实参。第一个是一个正则表达式。r'^$',其中r让Python将接下来的字符串视为原始字符串,而引号告诉Python正则表达式始于和终于何处。脱字符(^)让Python查看字符串的开头,而美元符号让Python查看字符串的末尾。总体而言,这个正则表达式让Python查找开头和末尾之间没有任何东西的URL。url的第二个实参指定了要调用的视图函数。第三个实参将这个URL模式的名称指定为index,让我们能够在代码的其他地方引用它。
18.3.2 编写视图
视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器。
learning_logs中的文件views.py是你执行命令python manage.py startapp时自动生成的,当前其内容如下:
from django.shortcuts import render # Create your views here.
为主页编写视图:
from django.shortcuts import render # Create your views here. def index(request): """学习笔记的主页""" return render(request,'learning_logs/index.html')
URL请求与我们刚才定义的模式匹配时,Django将在文件views.py中查找函数index,再将请求对象传递给这个视图函数。render()提供了两个实参:原始请求对象以及一个可用于创建网页的模板。下面来编写这个模板。
18.3.3 编写模板
在文件夹learning_logs中新建一个文件夹,并将其命名为templates。在文件夹templates中,再创建一个文件夹,并将其命名为learning_logs,在最里面的文件夹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网页。
18.4 创建其他网页
我们将创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页我们都将指定URL模式,编写一个视图函数,并编写一个模板。但这样做之前,先创建一个父模板,项目中的其他模板都继承它。
18.4.1 模板继承
1、父模板
首先创建一个名为base.html的模板,并将其存储在index.html所在目录中。这个文件包含所有页面都有的元素;其他模板都继承base.html。
<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> </p> {% block content %}{% endblock content %}
这个文件的第一部分创建一个包含项目名的段落,该段落也是一个到主页的链接。为创建链接,我们使用了一个模板标签,它是用大括号和百分号表示的。
在简单的HTML页面中,链接是使用锚标签定义的:
<a href='link_url>link text</a>
插入了块标签,这个快名为content,是一个占位符,其中包含的信息将由子模板指定。
2、子模板
现在需要重新编写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 %}
18.4.2 显示所有主题的页面
1、URL模式
首先,定义显示所有主题的页面的URL。修改learning_logs/urls.py:
"""定义learning_logs的URL模式""" from django.conf.urls import url from .import views urlpatterns = [ # 主页 url(r'^$',views.index,name='index'), # 显示所有的主题 url(r'^topics/$',views.topics,name='topics'), ]
我们只是在正则表达式中添加了topics/。Django检查请求的URL时,这个模式与这样的URL匹配:基础URL后面跟着topics。可以在末尾包含斜杠,也可以省略它,但单词topics后面不能有任何东西,否则就与该模式不匹配。其URL与该模式匹配的请求都将交给views.py中的函数topics()进行处理。
2、视图
函数topics()需要从数据库中获取一些数据,并将其发送给模板。我们需要在views.py中添加的代码如下:
from django.shortcuts import render from .models import Topic # Create your views here. 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)
3、模板
创建一个文件,将其命名为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 %}
这个网页的主体是一个项目列表,其中列出了用户输入的主题。在标准HTML中,项目列表被称为无序列表,用标签<ul></ul>表示。
在模块中,每个for循环都必须使用{% endfor %}标签来显示地指出其结束的位置。因此在模块中,循环类似于下面这样:
{% for item in list %} do something witn each item {% endfor %}
现在需要修改父模板,使其包含到显示所有主题的页面的链接:
<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> - <a href="{% url 'learning_logs:topics'%}">Topics</a> </p> {% block content %}{% endblock content %}
我们在主页的链接后面添加了一个连字符,然后添加了一个到显示所有主题的页面的链接。
现在如果刷新浏览器的主页,将看到链接Topics。单击这个链接,将看到:
18.4.3 显示特定主题的页面
接下来,我们需要创建一个专注于特定主题的页面——显示该主题的名称及该主题的所有条目。
1、URL模式
"""定义learning_logs的URL模式""" from django.conf.urls import url from .import views 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'), ]
2、视图
def topic(request,top_id): """显示单个主题及其所有的条目""" topic = Topic.objects.get(id=top_id) entries = topic.entry_set.order_by('-date_added') context = {'topic':topic,'entries':entries} return render(request,'learning_logs/topic.html',context)
date_added前面的减号指定降序排序。
3、模板
{% 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 %}
显示当前的主题,它存储在模板变量{{topic}}中。为什么使用变量topic呢?因为它包含在字典context中。
每个项目列表都将列出两项信息:条目的时间戳和完整的文本。未列出时间戳,我们显示属性gate_added的值。在Django模板中,竖线表示模板过滤器——对模板变量的值进行修改的函数。过滤器linebreaks将包含换行符的长条目转换为浏览器能够理解的格式,一面显示为一个不间断的文本块。
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.id%}">{{ topic }}</a> </li> {% empty %}} <li>No topics have been added yet.</li> {% endfor %} </ul> {% endblock content %}
---恢复内容结束---