基于Django3.0的web框架详细架构过程(一)


参考书籍《python编程:从入门到实践》十八章,十九章,二十章内容

该书籍Django使用1.11版本,而如今Django已经更新到3.0+,

因此本文将进行两种版本的对比并且匹配版本更迭导致的代码报错问题,一步一步带你实现适用Django3.0版本的web框架。

Django入门

当今的网站实际上都是富应用程序(rich application),就像成熟的桌面应用程序一样。Python提供了一组开发Web应用程序的卓越工具。在本文章中,你将学习如何使用Django(http://djangoproject.com/)来开发一个名为“学习笔记”(Learning Log)的项目,这是一个在线日志系统,让你能够记录所学习的有关特定主题的知识。

我们将为这个项目制定规范,然后为应用程序使用的数据定义模型。我们将使用Django的管理系统来输入一些初始数据,再学习编写视图和模板,让Django能够为我们的网站创建网页。Django是一个Web框架——一套用于帮助开发交互式网站的工具。Django能够响应网页请求,还能让你更轻松地读写数据库、管理用户等。在第19章和第20章,我们将改进“学习笔记”项目,再将其部署到活动的服务器,让你和你的朋友能够使用它。

一、建立项目

建立项目时,首先需要以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目。

(一)制定规范

完整的规范详细说明了项目的目标,阐述了项目的功能,并讨论了项目的外观和用户界面。与任何良好的项目规划和商业计划书一样,规范应突出重点,帮助避免项目偏离轨道。这里不会制定完整的项目规划,而只列出一些明确的目标,以突出开发的重点。我们制定的规范如下:

我们要编写一个名为“学习笔记”的Web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,就可创建新主题、添加新条目以及阅读既有的条目。学习新的主题时,记录学到的知识可帮助跟踪和复习这些知识。优秀的应用程序让这个记录过程简单易行。

(二)建立虚拟环境

要使用Django,首先需要建立一个虚拟工作环境。虚拟环境是系统的一个位置,你可以在其中安装包,并将其与其他Python包隔离。将项目的库与其他项目分离是有益的,且为了在第20章将“学习笔记”部署到服务器,这也是必须的。

为项目新建一个目录,将其命名为learning_log,再在终端中切换到这个目录,并创建一个虚拟环境。如果你使用的是Python3,可使用如下命令来创建虚拟环境:

image-20210306215725707

这里运行了模块venv,并使用它来创建一个名为ll_env的虚拟环境。如果这样做管用,请跳到后面的18.1.4节;如果不管用,请阅读18.1.3节。

(三)安装virtualenv

如果你使用的是较早的Python版本,或者系统没有正确地设置,不能使用模块venv,可安装virtualenv包。为此,可执行如下命令:

pip3 install --user virtualenv

别忘了,对于这个命令,你可能需要使用稍微不同的版本(如果你没有使用过pip,请参阅12.2.1节)。

注意 如果你使用的是Linux系统,且上面的做法不管用,可使用系统的包管理器来安装virtualenv。例如,要在Ubuntu系统中安装virtualenv,可使用命令sudo apt-getinstall python-virtualenv。

在终端中切换到目录learning_log,并像下面这样创建一个虚拟环境:

image-20210306220146051

注意 如果你的系统安装了多个Python版本,需要指定virtualenv使用的版本。例如,命令virtualenv ll_env –python=python3创建一个使用Python 3的虚拟环境。

win10可用

python3 -m virtualenv 11_env

来创建

(四)激活虚拟环境

建立虚拟环境后,需要使用下面的命令激活它:

image-20210306220424250

这个命令运行ll_env/bin中的脚本activate。环境处于活动状态时,环境名将包含在括号内,如❶处所示。在这种情况下,你可以在环境中安装包,并使用已安装的包。你在ll_env中安装的包仅在该环境处于活动状态时才可用。

注意 如果你使用的是Windows系统,请使用命令ll_env\Scripts\activate(不包含source)来激活这个虚拟环境。

若报错请使用完整的路径

E:\科技创新项目\djange框架\learning_log\11_env\Scripts\activate

要停止使用虚拟环境,可执行命令deactivate:

E:\科技创新项目\djange框架\learning_log\11_env\Scripts\deactivate

image-20210306221052970

如果关闭运行虚拟环境的终端,虚拟环境也将不再处于活动状态。

(五)安装Django

创建并激活虚拟环境后,就可安装Django了:

image-20210307140107209

由于我们是在虚拟环境中工作,因此在所有的系统中,安装Django的命令都相同:不需要指定标志–user,也无需使用python -m pip install package_name这样较长的命令。

别忘了,Django仅在虚拟环境处于活动状态时才可用。

(六)在Django中创建项目

在依然处于活动的虚拟环境的情况下(ll_env包含在括号内),执行如下命令来新建一个项目:

django-admin startproject learning_log .

该处的命令让Django新建一个名为learning_log的项目。这个命令末尾的句点让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器。

注意 千万别忘了这个句点,否则部署应用程序时将遭遇一些配置问题。如果忘记了这个句点,就将创建的文件和文件夹删除(ll_env除外),再重新运行这个命令。

注意windows下ls指令无法使用,要用dir查看目录下所有文件

image-20210307142102148

该处运行了命令ls(在Windows系统上应为dir),结果表明Django新建了一个名为learning_log的目录。它还创建了一个名为manage.py的文件,这是一个简单的程序,它接受命令并将其交给Django的相关部分去运行。我们将使用这些命令来管理诸如使用数据库和运行服务器等任务。

目录learning_log包含4个文件(见上),其中最重要的是settings.py、urls.py和wsgi.py。文件settings.py指定Django如何与你的系统交互以及如何管理项目。在开发项目的过程中,我们将修改其中一些设置,并添加一些设置。文件urls.py告诉Django应创建哪些网页来响应浏览器请求。文件wsgi.py帮助Django提供它创建的文件,这个文件名是web server gatewayinterface(Web服务器网关接口)的首字母缩写。

(七)创建数据库

Django将大部分与项目相关的信息都存储在数据库中,因此我们需要创建一个供Django使用的数据库。为给项目“学习笔记”创建数据库,请在处于活动虚拟环境中的情况下执行下面的命令:

python3 manage.py migrate

下图中的该处Django指出它将创建必要的数据库表,用于存储我们将在这个项目(Synchronizeunmigrated apps,同步未迁移的应用程序)中使用的信息,再确保数据库结构与当前代码(Apply all migrations,应用所有的迁移)匹配。

image-20210307142102148

我们将修改数据库称为迁移数据库。首次执行命令migrate时,将让Django确保数据库与项目的当前状态匹配。在使用SQLite(后面将更详细地介绍)的新项目中首次执行这个命令时,Django将新建一个数据库。

上图中的命令中,Django指出它将创建必要的数据库表,用于存储我们将在这个项目(Synchronizeunmigrated apps,同步未迁移的应用程序)中使用的信息,再确保数据库结构与当前代码(Apply all migrations,应用所有的迁移)匹配。

接着,我们运行了命令dir,其输出表明Django又创建了一个文件——db.sqlite3。SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,因为它让你不用太关注数据库管理的问题。

(八)查看项目

下面来核实Django是否正确地创建了项目。为此,可执行命令runserver,如下所示:

python3 manage.py runserver

image-20210307143629157

Django启动一个服务器,让你能够查看系统中的项目,了解它们的工作情况。当你在浏览器中输入URL以请求网页时,该Django服务器将进行响应:生成合适的网页,并将其发送给浏览器。

在❶处,Django通过检查确认正确地创建了项目;在❷处,它指出了使用的Django版本以及当前使用的设置文件的名称;在❸处,它指出了项目的URL。URL http://127.0.0.1:8000/表明项目将在你的计算机(即localhost)的端口8000上侦听请求。localhost是一种只处理当前系统发出的请求,而不允许其他任何人查看你正在开发的网页的服务器。

现在打开一款Web浏览器,并输入URL:http://localhost:8000/;如果这不管用,请输入http://127.0.0.1:8000/。你将看到类似于下图所示的页面,这个页面是Django创建的,让你知道到目前为止一切正常。现在暂时不要关闭这个服务器。若要关闭这个服务器,按Ctrl+C即可。

image-20210307144232873

注意 如果出现错误消息“That port is already in use”(指定端口已被占用),请执行命令python manage.pyrunserver 8001,让Diango使用另一个端口;如果这个端口也不可用,请不断执行上述命令,并逐渐增大其中的端口号,直到找到可用的端口。

动手试一试

18-1 新项目:

为更深入地了解Django做了些什么,可创建两个空项目,看看Django创建了什么。新建一个文件夹,并给它指定简单的名称,如InstaBook或FaceGram(不要在目录learning_log中新建该文件夹),在终端中切换到该文件夹,并创建一个虚拟环境。在这个虚拟环境中安装Django,并执行命令django-admin.py startprojectinstabook.(千万不要忘了这个命令末尾的句点)。

看看这个命令创建了哪些文件和文件夹,并与项目“学习笔记”包含的文件和文件夹进行比较。这样多做几次,直到对Django新建项目时创建的东西了如指掌。然后,将项目目录删除——如果你想这样做的话。

二、创建应用程序

Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。我们暂时只创建一个应用程序,它将完成项目的大部分工作。在第19章,我们将再添加一个管理用户账户的应用程序。

当前,在前面打开的终端窗口中应该还运行着runserver。请再打开一个终端窗口(或标签页),并切换到manage.py所在的目录。激活该虚拟环境,再执行命令startapp:

python3 manage.py startapp learning_logs

image-20210307154206402

命令startapp appname让Django建立创建应用程序所需的基础设施。

如果现在查看项目目录,将看到其中新增了一个文件夹learning_logs(见❶)。打开这个文件夹,看看Django都创建了什么(见❷)。其中最重要的文件是models.py、admin.py和views.py。我们将使用models.py来定义我们要在应用程序中管理的数据。admin.py和views.py将在稍后介绍。

(一)定义模型

我们来想想涉及的数据。每位用户都需要在学习笔记中创建很多主题。用户输入的每个条目都与特定主题相关联,这些条目将以文本的方式显示。我们还需要存储每个条目的时间戳,以便能够告诉用户各个条目都是什么时候创建的。

打开文件models.py,看看它当前包含哪些内容:

models.py

image-20210307155311360

这为我们导入了模块models,还让我们创建自己的模型。模型告诉Django如何处理应用程序中存储的数据。在代码层面,模型就是一个类,就像前面讨论的每个类一样,包含属性和方法。下面是表示用户将要存储的主题的模型:

from django.db import models

# 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

image-20210307160948131

我们创建了一个名为Topic的类,它继承了Model——Django中一个定义了模型基本功能的类。Topic类只有两个属性:text和date_added。属性text是一个CharField——由字符或文本组成的数据(见❶)。需要存储少量的文本,如名称、标题或城市时,可使用CharField。定义CharField属性时,必须告诉Django该在数据库中预留多少空间。在这里,我们将max_length设置成了200(即200个字符),这对存储大多数主题名来说足够了。

属性date_added是一个DateTimeField——记录日期和时间的数据(见❷)。我们传递了实参auto_now_add=True,每当用户创建新主题时,这都让Django将这个属性自动设置成当前日期和时间。

注意 要获悉可在模型中使用的各种字段,请参阅DjangoModel Field Reference(Django模型字段参考),其网址为https://docs.djangoproject.com/en/1.8/ref/models/fields/。就当前而言,你无需全面了解其中的所有内容,但自己开发应用程序时,这些内容会提供极大的帮助。

我们需要告诉Django,默认应使用哪个属性来显示有关主题的信息。Django调用方法str()来显示模型的简单表示。在这里,我们编写了方法str(),它返回存储在属性text中的字符串(见❸)。

注意 如果你使用的是Python 2.7,应调用方法unicode(),而不是str(),但其中的代码相同。

(二)激活模型

要使用模型,必须让Django将应用程序包含到项目中。为此,打开settings.py(它位于目录learning_log/learning_log中),你将看到一个这样的片段,即告诉Django哪些应用程序安装在项目中:

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

image-20210307170740014

这是一个元组,告诉Django项目是由哪些应用程序组成的。请将INSTALLED_APPS修改成下面这样,将前面的应用程序添加到这个元组中:

image-20210307174623657

INSTALLED_APPS = [
    --snip-- #省略上面代码
    'django.contrib.staticfiles',
    #我的应用程序
    'learning_logs',
]

通过将应用程序编组,在项目不断增大,包含更多的应用程序时,有助于对应用程序进行跟踪。这里新建了一个名为Myapps的片段,当前它只包含应用程序learning_logs。接下来,需要让Django修改数据库,使其能够存储与模型Topic相关的信息。为此,在终端窗口中执行下面的命令:

python3 manage.py makemigrations learning_logs

注意:

如果出现

LookupError: No installed app with label 'admin'.

的报错,则说明是上面的settings.py文件设置格式出现错误

image-20210307193335606

命令makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型Topic创建一个表。

下面来应用这种迁移,让Django替我们修改数据库:

python3 manage.py migrate

image-20210307194038969

这个命令的大部分输出都与我们首次执行命令migrate的输出相同。我们需要检查的是❶处的输出行,在这里,Django确认为learning_logs应用迁移时一切正常(OK)。

每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。

(三)Django管理网站

为应用程序定义模型时,Django提供的管理网站(adminsite)让你能够轻松地处理模型。网站的管理员可使用管理网站,但普通用户不能使用。在本节中,我们将建立管理网站,并通过它使用模型Topic来添加一些主题。

1.创建超级用户

Django允许你创建具备所有权限的用户——超级用户。权限决定了用户可执行的操作。最严格的权限设置只允许用户阅读网站的公开信息;注册了的用户通常可阅读自己的私有数据,还可查看一些只有会员才能查看的信息。为有效地管理Web应用程序,网站所有者通常需要访问网站存储的所有信息。优秀的管理员会小心对待用户的敏感信息,因为用户对其访问的应用程序有极大的信任。

为在Django中创建超级用户,请执行下面的命令并按提示做:

python3 manage.py createsuperuser

image-20210307200148903

你执行命令createsuperuser时,Django提示你输入超级用户的用户名(见❶)。这里我们输入的是ll_admin,但你可以输入任何用户名,比如电子邮件地址,也可让这个字段为空(见❷)。你需要输入密码两次(见❸)。

注意 可能会对网站管理员隐藏有些敏感信息。例如,Django并不存储你输入的密码,而存储从该密码派生出来的一个字符串——散列值。每当你输入密码时,Django都计算其散列值,并将结果与存储的散列值进行比较。如果这两个散列值相同,就通过了身份验证。通过存储散列值,即便黑客获得了网站数据库的访问权,也只能获取其中存储的散列值,而无法获得密码。在网站配置正确的情况下,几乎无法根据散列值推导出原始密码。

2.向管理网站注册模型

Django自动在管理网站中添加了一些模型,如User和Group,但对于我们创建的模型,必须手工进行注册。

我们创建应用程序learning_logs时,Django在models.py所在的目录中创建了一个名为admin.py的文件:

admin.py

from django.contrib import admin

# Register your models here.
from learning_logs.models import Topic
admin.site.register(Topic)

image-20210307203319723

这些代码导入我们要注册的模型Topic(见❶),再使用admin.site.register()(见❷)让Django通过管理网站管理我们的模型。

现在,使用超级用户账户访问管理网站:访问http://localhost:8000/admin/,并输入你刚创建的超级用户的用户名和密码,你将看到类似于下图所示的屏幕。这个网页让你能够添加和修改用户和用户组,还可以管理与刚才定义的模型Topic相关的数据。

包含模型Topic的管理网站

注意 如果你在浏览器中看到一条消息,指出访问的网页不可用,请确认你在终端窗口中运行着Django服务器。如果没有,请激活虚拟环境,并执行命令python manage.py runserver。

3.添加主题

向管理网站注册Topic后,我们来添加第一个主题。为此,单击Topics进入主题网页,它几乎是空的,这是因为我们还没有添加任何主题。单击Add,你将看到一个用于添加新主题的表单。在第一个方框中输入Chess,再单击Save,这将返回到主题管理页面,其中包含刚创建的主题。下面再创建一个主题,以便有更多的数据可供使用。再次单击Add,并创建另一个主题Rock Climbing。当你单击Save时,将重新回到主题管理页面,其中包含主题Chess和RockClimbing。

(四)定义模型Entry

要记录学到的国际象棋和攀岩知识,需要为用户可在学习笔记中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一个主题。

下面是模型Entry的代码:

models.py

from django.db import models
class Topic(models. Model) :
    --snip--
class Entry(models.Model):"""学到的有关某个主题的具体知识"""
    topic = models.ForeignKey(Topic)❷
    text = models.TextField()❸
    date_added = models.DateTimeField(auto_now_add=True)
    class Meta: ❹
        verbose_name_plural = 'entries'
    def __str__(self) :
        """返回模型的字符串表示"""
        return self.text[:50]+"..."

像Topic一样,Entry也继承了Django基类Model(见❶)。第一个属性topic是一个ForeignKey实例(见❷)。外键是一个数据库术语,它引用了数据库中的另一条记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时,Django使用与每项信息相关联的键。稍后我们将根据这些联系获取与特定主题相关联的所有条目。

接下来是属性text,它是一个TextField实例(见❸)。这种字段不需要长度限制,因为我们不想限制条目的长度。属性date_added让我们能够按创建顺序呈现条目,并在每个条目旁边放置时间戳。

在❹处,我们在Entry类中嵌套了Meta类。Meta存储用于管理模型的额外信息,在这里,它让我们能够设置一个特殊属性,让Django在需要时使用Entries来表示多个条目。如果没有这个类, Django将使用Entrys来表示多个条目。最后,方法str()告诉Django,呈现条目时应显示哪些信息。由于条目包含的文本可能很长,我们让Django只显示text的前50个字符(见❺)。我们还添加了一个省略号,指出显示的并非整个条目。

(五)迁移模型Entry

由于我们添加了一个新模型,因此需要再次迁移数据库。你将慢慢地对这个过程了如指掌:

修改models.py,执行命令

python manage.py makemigrations app_name

出现报错

TypeError: __init__() missing 1 required positional argument: 'on_delete'

解决方案:
定义外键的时候需要加上 on_delete=;
即:contract = models.ForeignKey(Contract, on_delete=models.CASCADE)

原因如下:
django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常:
TypeError: init() missing 1 required positional argument: ‘on_delete’

on_delete各个参数的含义如下:

on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
# models.ForeignKey(‘关联表’, on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
# models.ForeignKey(‘关联表’, on_delete=models.SET_DEFAULT, default=’默认值’)
on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
on_delete=models.SET, # 删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

image-20210308203811344

修改后,再执行命令成功

python3 manage.py migrate

下面来迁移数据库并查看输出:

image-20210308205019813

生成了一个新的迁移文件——0002_entry.py,它告诉Django如何修改数据库,使其能够存储与模型Entry相关的信息(见❶)。执行命令migrate,我们发现Django应用了这种迁移且一切顺利(见❷)。

(六)向管理网站注册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:8000/admin/,你将看到learning_logs下列出了Entries。单击Entries的Add链接,或者单击Entries再选择Add entry。你将看到一个下拉列表,让你能够选择要为哪个主题创建条目,还有一个用于输入条目的文本框。从下拉列表中选择Chess,并添加一个条目。下面是我添加的第一个条目。

The opening is the first part of the game, roughly thefirst ten moves or so. In the opening, it’s a good ideato do three things— bring out your bishops andknights, try to control the center of the board, andcastle your king.(国际象棋的第一个阶段是开局,大致是前10步左右。在开局阶段,最好做三件事情:将象和马调出来;努力控制棋盘的中间区域;用车将王护住。)Of course, these are just guidelines. It will beimportant to learn when to follow these guidelinesand when to disregard these suggestions.(当然,这些只是指导原则。学习什么情况下遵守这些原则、什么情况下不用遵守很重要。)

当你单击Save时,将返回到主条目管理页面。在这里,你将发现使用text[:50]作为条目的字符串表示的好处:管理界面中,只显示了条目的开头部分而不是其所有文本,这使得管理多个条目容易得多。

再来创建一个国际象棋条目,并创建一个攀岩条目,以提供一些初始数据。下面是第二个国际象棋条目。

In the opening phase of the game, it’s important tobring out your bishops and knights. These pieces arepowerful and maneuverable enough to play asignificant role in the beginning moves of a game.(在国际象棋的开局阶段,将象和马调出来很重要。这些棋子威力大,机动性强,在开局阶段扮演着重要角色。)

下面是第一个攀岩条目:

One of the most important concepts in climbing is tokeep your weight on your feet as much as possible.There’s a myth that climbers can hang all day on theirarms. In reality, good climbers have practiced specificways of keeping their weight over their feet wheneverpossible.(最重要的攀岩概念之一是尽可能让双脚承受体重。有谬误认为攀岩者能依靠手臂的力量坚持一整天。实际上,优秀的攀岩者都经过专门训练,能够尽可能让双脚承受体重。)

继续往下开发“学习笔记”时,这三个条目可为我们提供使用的数据。

(七)Django shell

输入一些数据后,就可通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell,是测试项目和排除其故障的理想之地。下面是一个交互式shell会话示例:

python3 manage.py shell
from learning_logs.models import Topic

Topic.objects.all()

image-20210309171149682

在活动的虚拟环境中执行时,命令python manage.py shell启动一个Python解释器,可使用它来探索存储在项目数据库中的数据。在这里,我们导入了模块learning_logs.models中的模型Topic(见❶),然后使用方法Topic.objects.all()来获取模型Topic的所有实例;它返回的是一个列表,称为查询集(queryset)。

我们可以像遍历列表一样遍历查询集。下面演示了如何查看分配给每个主题对象的ID:

topics = Topic.objects.all()
for topic in topics:
    print(topic.id,topic)

image-20210309172453359

我们将返回的查询集存储在topics中,然后打印每个主题的id属性和字符串表示。从输出可知,主题Chess的ID为1,而RockClimbing的ID为2。

知道对象的ID后,就可获取该对象并查看其任何属性。下面来看看主题Chess的属性text和date_added的值:

t = Topic.objects.get(id=1)
t.text
t.date_added

image-20210309172741839

我们还可以查看与主题相关联的条目。前面我们给模型Entry定义了属性topic,这是一个ForeignKey,将条目与主题关联起来。利用这种关联,Django能够获取与特定主题相关联的所有条目,如下所示:

t.entry_set.all()

image-20210309172951882

为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set(见❶)。例如,假设你有模型Pizza和Topping,而Topping通过一个外键关联到Pizza;如果你有一个名为my_pizza的对象,表示一张比萨,就可使用代码my_pizza.topping_set.all()来获取这张比萨的所有配料。

编写用户可请求的网页时,我们将使用这种语法。确认代码能获取所需的数据时,shell很有帮助。如果代码在shell中的行为符合预期,那么它们在项目文件中也能正确地工作。如果代码引发了错误或获取的数据不符合预期,那么在简单的shell环境中排除故障要比在生成网页的文件中排除故障容易得多。我们不会太多地使用shell,但应继续使用它来熟悉对存储在项目中的数据进行访问的Django语法。

注意 每次修改模型后,你都需要重启shell,这样才能看到修改的效果。要退出shell会话,可按Ctr+D;如果你使用的是Windows系统,应按Ctr+Z,再按回车键。

动手试一试

18-2 简短的条目:

当前,Django在管理网站或shell中显示Entry实例时,模型Entry的方法str()都在它的末尾加上省略号。请在方法str()中添加一条if语句,以便仅在条目长度超过50字符时才添加省略号。使用管理网站来添加一个长度少于50字符的条目,并核实显示它时没有省略号。

18-3 Django API:

编写访问项目中的数据的代码时,你编写的是查询。请浏览有关如何查询数据的文档,其网址为https://docs.djangoproject.com/en/7.8/topics/db/queries/。其中大部分内容都是你不熟悉的,但等你自己开发项目时,这些内容会很有用。

18-4 比萨店:

新建一个名为pizzeria的项目,并在其中添加一个名为pizzas的应用程序。定义一个名为Pizza的模型,它包含字段name,用于存储比萨名称,如Hawaiian和Meat Lovers。定义一个名为Topping的模型,它包含字段pizza和name,其中字段pizza是一个关联到Pizza的外键,而字段name用于存储配料,如pineapple、Canadianbacon和sausage。

向管理网站注册这两个模型,并使用管理网站输入一些比萨名和配料。使用shell来查看你输入的数据。

三、创建网页:

学习笔记主页使用Django创建网页的过程通常分三个阶段:定义URL、编写视图和编写模板。首先,你必须定义URL模式。URL模式描述了URL是如何设计的,让Django知道如何将浏览器请求与网站URL匹配,以确定返回哪个网页。

每个URL都被映射到特定的视图——视图函数获取并处理网页所需的数据。视图函数通常调用一个模板,后者生成浏览器能够理解的网页。为明白其中的工作原理,我们来创建学习笔记的主页。我们将定义该主页的URL、编写其视图函数并创建一个简单的模板。

鉴于我们只是要确保“学习笔记”按要求的那样工作,我们将暂时让这个网页尽可能简单。Web应用程序能够正常运行后,设置样式可使其更有趣,但中看不中用的应用程序毫无意义。就目前而言,主页只显示标题和简单的描述。

(一)映射URL

用户通过在浏览器中输入URL以及单击链接来请求网页,因此我们需要确定项目需要哪些URL。主页的URL最重要,它是用户用来访问项目的基础URL。当前,基础URL(http://localhost:8000/)返回默认的Django网站,让我们知道正确地建立了项目。我们将修改这一点,将这个基础URL映射到“学习笔记”的主页。

打开项目主文件夹learning_log中的文件urls.py,你将看到如下代码:

from django.contrib import admin❶
from django.urls import path

urlpatterns = [❷
    path('admin/', admin.site.urls),]

前两行导入了为项目和管理网站管理URL的函数和模块(见❶)。这个文件的主体定义了变量urlpatterns(见❷)。在这个针对整个项目的urls.py文件中,变量urlpatterns包含项目中的应用程序的URL。❸处的代码包含模块admin.site.urls,该模块定义了可在管理网站中请求的所有URL。

我们需要包含learning_logs的URL:

原有代码

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

修改后

from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
    url(r'^admin/',include(admin.site.urls)),
    url (r'', include('learning_logs.urls',namespace='learning_logs')),]

在❶处,我们添加了一行代码来包含模块learning_logs.urls。这行代码包含实参namespace,让我们能够将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'),]

为弄清楚当前位于哪个urls.py文件中,我们在这个文件开头添加了一个文档字符串(见❶)。接下来,我们导入了函数url,因为我们需要使用它来将URL映射到视图(见❷)。我们还导入了模块views(见❸),其中的句点让Python从当前的urls.py模块所在的文件夹中导入视图。在这个模块中,变量urlpatterns是一个列表,包含可在应用程序learning_logs中请求的网页(见❹)。

实际的URL模式是一个对函数url()的调用,这个函数接受三个实参(见❺)。第一个是一个正则表达式。Django在urlpatterns中查找与请求的URL字符串匹配的正则表达式,因此正则表达式定义了Django可查找的模式。

我们来看看正则表达式r'^$'。其中的r让Python将接下来的字符串视为原始字符串,而引号告诉Python正则表达式始于和终于何处。脱字符(^)让Python查看字符串的开头,而美元符号让Python查看字符串的末尾。总体而言,这个正则表达式让Python查找开头和末尾之间没有任何东西的URL。Python忽略项目的基础URL(http://localhost:8000/),因此这个正则表达式与基础URL匹配。其他URL都与这个正则表达式不匹配。如果请求的URL不与任何URL模式匹配,Django将返回一个错误页面。

url()的第二个实参(见❺)指定了要调用的视图函数。请求的URL与前述正则表达式匹配时,Django将调用views.index(这个视图函数将在下一节编写)。第三个实参将这个URL模式的名称指定为index,让我们能够在代码的其他地方引用它。每当需要提供到这个主页的链接时,我们都将使用这个名称,而不编写URL。

注意:

以上教程为Django1.11

在django2.0后不支持使用在urls.py中写

url(r'^admin/', include(admin.site.urls))

runserver后会发生报错

image-20210309202615597

,直接用

path('admin/', admin.site.urls)

,
对于应用中自定义urls.py文件的引用还是需要使用include()

百度一下得到改进办法

首先要修改learning_log\urls.py

from django.contrib import admin
# from django.conf.urls import include, url
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('learning_logs.urls', namespace='learning_logs')),
    # url(r'^admin/', include(admin.site.urls)),
    # url(r'', include('learning_logs.urls', namespace='learning_logs')),Django2.0使用django.urls.path
]

但只加入namespace会报错,必须在learning_logs\urls.py中定义变量app_name才行

learning_logs\urls.py

from django.urls import path, include, re_path

from . import views

urlpatterns = [
    # url(r'^$', views.index, name='index'),
    re_path('^$', views.index, name='index')
]

app_name = 'learning_logs'

然后再运行runserver就不会出错了

注意 正则表达式通常被称为regex,几乎每种编程语言都使用它。它们的用途多得难以置信,但需要经过一定的练习才能熟悉。如果你不明白前面介绍的内容,也不用担心,你在完成这个项目的过程中,将会看到很多正则表达式。

(二)编写视图

视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器——这通常是使用定义了网页是什么样的模板实现的。

learning_logs中的文件views.py是你执行命令python manage.py startapp时自动生成的,当前其内容如下:

image-20210309181505592

当前,这个文件只导入了函数render(),它根据视图提供的数据渲染响应。下面的代码演示了该如何为主页编写视图:

from django.shortcuts import render
def index(request):
    """学习笔记的主页"""
    return render(request,'learning_logs/index.html')

URL请求与我们刚才定义的模式匹配时,Django将在文件views.py中查找函数index(),再将请求对象传递给这个视图函数。在这里,我们不需要处理任何数据,因此这个函数只包含调用render()的代码。这里向函数render()提供了两个实参:原始请求对象以及一个可用于创建网页的模板。下面来编写这个模板。

18.3.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>

这个文件非常简单。对于不熟悉HTML的读者,这里解释一下:

标签<p></p>标识段落;标签<p>指出了段落的开头位置,而标签</p>指出了段落的结束位置。这里定义了两个段落:第一个充当标题,第二个阐述了用户可使用“学习笔记”来做什么。

现在,如果你请求这个项目的基础URL——http://localhost:8000/,将看到刚才创建的网页,而不是默认的Django网页。Django接受请求的URL,发现该URL与模式`r'^$'`匹配,因此调用函数views.index(),这将使用index.html包含的模板来渲染网页,结果如下图所示。

image-20210309210605104

创建网页的过程看起来可能很复杂,但将URL、视图和模板分离的效果实际上很好。这让我们能够分别考虑项目的不同方面,且在项目很大时,让各个参与者可专注于其最擅长的方面。例如,数据库专家可专注于模型,程序员可专注于视图代码,而Web设计人员可专注于模板。

动手试一试

18-5 膳食规划程序:

假设你要创建一个应用程序,帮助用户规划一周的膳食。为此,新建一个文件夹,并将其命名为meal_planner,再在这个文件夹中新建一个Django项目。接下来,新建一个名为meal_plans的应用程序,并为这个项目创建一个简单的主页。

18-6 比萨店主页:

在你为完成练习18-4而创建的项目Pizzeria中,添加一个主页。

四、创建其他网页

制定创建网页的流程后,可以开始扩充“学习笔记”项目了。我们将创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定URL模式,编写一个视图函数,并编写一个模板。但这样做之前,我们先创建一个父模板,项目中的其他模板都将继承它。

(一)模板继承

创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。这种方法能让你专注于开发每个网页的独特方面,还能让修改项目的整体外观容易得多。

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模式。

在简单的HTML页面中,链接是使用锚标签定义的:

<a href="link_url">link text</a>

让模板标签来生成URL,可让链接保持最新容易得多。要修改项目中的URL,只需修改urls.py中的URL模式,这样网页被请求时,Django将自动插入修改后的URL。在我们的项目中,每个网页都将继承base.html,因此从现在开始,每个网页都包含到主页的链接。

在❶处,我们插入了一对块标签。这个块名为content,是一个占位符,其中包含的信息将由子模板指定。

子模板并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。

注意 在Python代码中,我们几乎总是缩进四个空格。相比于Python文件,模板文件的缩进层级更多,因此每个层级通常只缩进两个空格。

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 %}❸

如果将这些代码与原来的index.html进行比较,可发现我们将标题Learning Log替换成了从父模板那里继承的代码(见❶)。子模板的第一行必须包含标签{ % extends % },让Django知道它继承了哪个父模板。文件base.html位于文件夹learning_logs中,因此父模板路径中包含learning_logs。这行代码导入模板base.html的所有内容,让index.html能够指定要在content块预留的空间中添加的内容。

在❷处,我们插入了一个名为content的{ % block % }标签,以定义content块。不是从父模板继承的内容都包含在content块中,在这里是一个描述项目“学习笔记”的段落。在❸处,我们使用标签{ % endblock content % }指出了内容定义的结束位置。

模板继承的优点开始显现出来了:在子模板中,只需包含当前网页特有的内容。这不仅简化了每个模板,还使得网站修改起来容易得多。要修改很多网页都包含的元素,只需在父模板中修改该元素,你所做的修改将传导到继承该父模板的每个页面。在包含数十乃至数百个网页的项目中,这种结构使得网站改进起来容易而且快捷得多。

注意 在大型项目中,通常有一个用于整个网站的父模板——base.html,且网站的每个主要部分都有一个父模板。每个部分的父模板都继承base.html,而网站的每个网页都继承相应部分的父模板。这让你能够轻松地修改整个网站的外观、网站任何一部分的外观以及任何一个网页的外观。这种配置提供了一种效率极高的工作方式,让你乐意不断地去改进网站。

(二)显示所有主题的页面

有了高效的网页创建方法,就能专注于另外两个网页了:显示全部主题的网页以及显示特定主题中条目的网页。所有主题页面显示用户创建的所有主题,它是第一个需要使用数据的网页。

1.URL模式

首先,我们来定义显示所有主题的页面的URL。通常,使用一个简单的URL片段来指出网页显示的信息;我们将使用单词topics,因此URLhttp://localhost:8000/topics/将返回显示所有主题的页面。下面演示了该如何修改learning_logs/urls.py:

"""定义learning_ logs的URL模式"""
from django.urls import path, include, re_path
from . import views
urlpatterns = [
    # 主页
    # url(r'^$', views.index, name='index'),
    re_path('^$', views.index, name='index'),

    #url(r'^topics/$',views.topics,name='topics'),
    path('topics/',views.topics,name='topics'),]

app_name = 'learning_logs'

我们只是在用于主页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):
-- snip--
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. <!--1i-->
{% endfor %}❺
</li></ul>❻
{% endblock content %}

就像模板index.html一样,我们首先使用标签{ % extends % }来继承base.html,再开始定义content块。这个网页的主体是一个项目列表,其中列出了用户输入的主题。在标准HTML中,项目列表被称为无序列表,用标签<ul></ul>表示。包含所有主题的项目列表始于❶处。

在❷处,我们使用了一个相当于for循环的模板标签,它遍历字典context中的列表topics。模板中使用的代码与Python代码存在一些重要差别:Python使用缩进来指出哪些代码行是for循环的组成部分,而在模板中,每个for循环都必须使用{ % endfor %}标签来显式地指出其结束位置。因此在模板中,循环类似于下面这样:

{% foritem in list %}
do something with each item
{% endfor %}

在循环中,我们要将每个主题转换为一个项目列表项。要在模板中打印变量,需要将变量名用双花括号括起来。每次循环时,❸处的代码{ { topic } }都被替换为topic的当前值。这些花括号不会出现在网页中,它们只是用于告诉Django我们使用了一个模板变量。HTML标签<li></li>表示一个项目列表项,在标签对<ul></ul>内部,位于标签<li></li>之间的内容都是一个项目列表项。

在❹处,我们使用了模板标签{ % empty % },它告诉Django在列表topics为空时该怎么办:这里是打印一条消息,告诉用户还没有添加任何主题。最后两行分别结束for循环(见❺)和项目列表(见❻)。

现在需要修改父模板,使其包含到显示所有主题的页面的链接:

image-20210311162123896

我们在到主页的链接后面添加了一个连字符(见❶),然后添加了一个到显示所有主题的页面的链接——使用的也是模板标签url(见❷)。这一行让Django生成一个链接,它与learning_logs/ urls.py中名为topics的URL模式匹配。

现在如果你刷新浏览器中的主页,将看到链接Topics。单击这个链接,将看到类似于图18-4所示的网页。

image-20210311162244598

(三)显示特定主题的页面

接下来,我们需要创建一个专注于特定主题的页面——显示该主题的名称及该主题的所有条目。同样,我们将定义一个新的URL模式,编写一个视图并创建一个模板。我们还将修改显示所有主题的网页,让每个项目列表项都是一个链接,单击它将显示相应主题的所有条目。

1.URL模式

显示特定主题的页面的URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id属性来指出请求的是哪个主题。例如,如果用户要查看主题Chess(其id为1)的详细页面,URL将为http://localhost:8000/topics/1/。下面是与这个URL匹配的模式,它包含在learning_logs/urls.py中:

django1.11改法

image-20210311163054782

Django2.0改法:

我们来详细研究这个URL模式中的正则表达式——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()需要从数据库中获取指定的主题以及与之相关联的所有条目,如下所示:

views.py

--snip--
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 %}
  

Topic: {{ topic }}

Entries:

    ❷ {% for entry in entries %}❸
  • {{ entry.date_added|date:'M d, Y H:i'}}

    {{ entry.text|linebreaks }}

  • {% empty %}❻
  • There are no entries for this topic yet. {% endfor %}
{% endblock content %}

像这个项目的其他页面一样,这里也继承了base.html。接下来,我们显示当前的主题(见❶),它存储在模板变量{ { topic } }中。为什么可以使用变量topic呢?因为它包含在字典context中。接下来,我们开始定义一个显示每个条目的项目列表(见❷),并像前面显示所有主题一样遍历条目(见❸)。

每个项目列表项都将列出两项信息:条目的时间戳和完整的文本。为列出时间戳(见❹),我们显示属性date_added的值。在Django模板中,竖线(|)表示模板过滤器——对模板变量的值进行修改的函数。过滤器date: 'M d, Y H:i'以这样的格式显示时间戳:January 1, 2015 23:00。接下来的一行显示text的完整值,而不仅仅是entry的前50个字符。过滤器linebreaks(见❺)将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。在❻处,我们使用模板标签{ % empty % }打印一条消息,告诉用户当前主题还没有条目。

4.将显示所有主题的页面中的每个主题都设置为链接

在浏览器中查看显示特定主题的页面前,我们需要修改模板topics.html,让每个主题都链接到相应的网页,如下所示:

--snip--
    {% for topic in topics %}
      <li>
        <a href=" {% url 'learning_logs:topic' topic.id %}">{{ topic }} </a>
      </1i>
    {% empty %}
--snip--

我们使用模板标签url根据learning_logs中名为topic的URL模式来生成合适的链接。这个URL模式要求提供实参topic_id,因此我们在模板标签url中添加了属性topic.id。现在,主题列表中的每个主题都是一个链接,链接到显示相应主题的页面,如http://localhost:8000/topics/1/。

如果你刷新显示所有主题的页面,再单击其中的一个主题,将看到类似于下图所示的页面。

特定主题的详细页面,其中显示了该主题的所有条目

动手试一试

18-7 模板文档:

请浏览Django模板文档,其网址为https://docs.djangoproject.com/en/1.8/ref/templates/。自己开发项目时,可再回过头来参考该文档。

18-8 比萨店页面:

在练习18-6中开发的项目Pizzeria中添加一个页面,它显示供应的比萨的名称。然后,将每个比萨名称都设置成一个链接,单击这种链接将显示一个页面,其中列出了相应比萨的配料。请务必使用模板继承来高效地创建页面。

五、小结

在本章中,你首先学习了如何使用Django框架来创建Web应用程序。你制定了简要的项目规范,在虚拟环境中安装了Django,创建了一个项目,并核实该项目已正确地创建。你学习了如何创建应用程序,以及如何定义表示应用程序数据的模型。你学习了数据库,以及在你修改模型后,Django可为你迁移数据库提供什么样的帮助。你学习了如何创建可访问管理网站的超级用户,并使用管理网站输入了一些初始数据。

你还探索了Django shell,它让你能够在终端会话中处理项目的数据。你学习了如何定义URL、创建视图函数以及编写为网站创建网页的模板。最后,你使用了模板继承,它可简化各个模板的结构,并使得修改网站更容易。

在第19章,我们将创建对用户友好而直观的网页,让用户无需通过管理网站就能添加新的主题和条目,以及编辑既有的条目。我们还将添加一个用户注册系统,让用户能够创建账户和自己的学习笔记。让任意数量的用户都能与之交互,是Web应用程序的核心所在。


文章作者: lijunliang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lijunliang !
评论
 上一篇
从0到1:web入门(一)信息搜集 从0到1:web入门(一)信息搜集
古人云“知己知彼,百战不殆”,在现实世界和比赛中,信息搜集是前期的必备工作,也是重中之重。在CTF线上比赛的Web类题目中,信息搜集涵盖的面非常广,有备份文件、目录信息、Banner信息等,这就需要参赛者有丰富的经验,或者利用一些脚本来帮助自己发现题目信息、挖掘题目漏洞。本节会尽可能叙述在CTF线上比赛中Web类题目包含的信息搜集,也会推荐一些作者测试无误的开源工具软件。
下一篇 
零宽度字符加密 零宽度字符加密
​​ 简而言之,就是字节宽度为0的特殊字符.零宽度字符是一些不可见的,不可打印的字符。它们存在于页面中主要用于调整字符的显示格式。
2021-03-06
  目录