Django 简介
在这篇 Django 的第一篇文章中,我们将回答“什么是 Django?”这个问题,并为您概述这个 Web 框架的独特之处。
我们将概述主要功能,包括一些在本模块中没有时间详细介绍的进阶功能。我们还将向您展示 Django 应用程序的主要构建模块(虽然此时您还没有可以进行测试的开发环境)。
先决条件 | 对 服务器端网站编程 的一般理解,特别是对 网站中的客户端-服务器交互 机制的理解。 |
---|---|
目标 | 熟悉 Django 是什么,它提供了哪些功能,以及 Django 应用程序的主要构建模块。 |
什么是 Django?
Django 是一个高级 Python Web 框架,可以快速开发安全且可维护的网站。由经验丰富的开发人员构建,Django 承担了 Web 开发的大部分繁琐工作,因此您可以专注于编写您的应用程序,而无需重新发明轮子。它是免费且开源的,拥有一个蓬勃发展且活跃的社区、出色的文档,以及许多免费和付费支持选项。
Django 帮助您编写软件,这些软件是
- 完整的
-
Django 遵循“内置电池”理念,并提供几乎所有开发人员可能想要“开箱即用”的功能。由于您需要的一切都是同一个“产品”的一部分,因此它们无缝地协同工作,遵循一致的设计原则,并拥有广泛且 最新的文档。
- 通用的
-
Django 可以(并且已经)用于构建几乎任何类型的网站——从内容管理系统和维基百科,到社交网络和新闻网站。它可以与任何客户端框架一起工作,并且可以以几乎任何格式(包括 HTML、RSS 订阅、JSON 和 XML)交付内容。
在内部,虽然它为您可能需要的几乎任何功能提供了选择(例如,几个流行的数据库、模板引擎等),但它也可以扩展到在需要时使用其他组件。
- 安全的
-
Django 通过提供一个经过设计以“做正确的事情”以自动保护网站的框架,帮助开发人员避免许多常见的安全错误。例如,Django 提供了一种安全的方式来管理用户帐户和密码,避免常见的错误,例如将会话信息放在易受攻击的 cookie 中(cookie 只包含密钥,实际数据存储在数据库中)或直接存储密码而不是密码哈希值。
密码哈希值是通过将密码发送到 加密哈希函数 创建的固定长度值。Django 可以通过将输入的密码运行到哈希函数并将其输出与存储的哈希值进行比较来检查输入的密码是否正确。但是,由于该函数的“单向”性质,即使存储的哈希值被泄露,攻击者也很难找出原始密码。
Django 默认情况下可以防止许多漏洞,包括 SQL 注入、跨站点脚本、跨站点请求伪造和 点击劫持(有关此类攻击的更多详细信息,请参阅 网站安全)。
- 可扩展的
-
Django 使用基于组件的“无共享”架构(架构的每个部分都独立于其他部分,因此可以根据需要进行替换或更改)。在不同部分之间有明确的分隔意味着它可以通过在任何级别添加硬件来扩展以应对流量增加:缓存服务器、数据库服务器或应用程序服务器。一些最繁忙的网站已成功地扩展了 Django 以满足其需求(例如,Instagram 和 Disqus,仅举两例)。
- 可维护的
-
Django 代码是使用鼓励创建可维护且可重用代码的设计原则和模式编写的。特别是,它利用了“不要重复自己”(DRY)原则,因此没有不必要的重复,从而减少了代码量。Django 还提倡将相关功能分组到可重用的“应用程序”中,并在更低级别上将相关代码分组到模块中(类似于 模型视图控制器(MVC) 模式)。
- 便携式的
-
Django 是用 Python 编写的,Python 在许多平台上运行。这意味着您不受限于任何特定的服务器平台,并且可以在许多 Linux、Windows 和 macOS 版本上运行您的应用程序。此外,Django 得到许多 Web 托管提供商的良好支持,这些提供商通常会提供托管 Django 站点的特定基础设施和文档。
它从哪里来?
Django 最初是由一个 Web 团队在 2003 年到 2005 年间开发的,他们负责创建和维护报纸网站。在创建了多个网站后,该团队开始提取和重用许多常见的代码和设计模式。这些常用代码发展成为一个通用的 Web 开发框架,并于 2005 年 7 月作为“Django”项目开源。
Django 一直在不断发展和改进,从 2008 年 9 月的第一个里程碑版本(1.0)到 2023 年底的 5.0 版本。每次发布都添加了新的功能和错误修复,从支持新类型的数据库、模板引擎和缓存,到添加“通用”视图函数和类(减少了开发人员为许多编程任务编写的代码量)。
注意:查看 发布说明,了解 Django 网站上的最新版本发生了哪些变化,以及为使 Django 变得更好所付出的努力。
Django 现在是一个蓬勃发展的协作开源项目,拥有数千名用户和贡献者。虽然它仍然有一些反映其起源的功能,但 Django 已发展成为一个通用的框架,能够开发任何类型的网站。
Django 的流行程度如何?
目前还没有一种现成且明确的服务器端框架流行度的衡量标准(尽管您可以使用诸如统计每个平台的 GitHub 项目数量和 StackOverflow 问题数量之类的机制来估计流行度)。一个更好的问题是 Django 是否“足够流行”以避免不受欢迎平台的问题。它是否在不断发展?如果您需要帮助,您可以获得帮助吗?如果您学习 Django,您是否有机会获得报酬的工作?
根据使用 Django 的知名网站数量、贡献代码库的人数以及提供免费和付费支持的人数,答案是肯定的,Django 是一个流行的框架!
使用 Django 的知名网站包括:Disqus、Instagram、Knight 基金会、MacArthur 基金会、Mozilla、国家地理、开放知识基金会、Pinterest 和 Open Stack(来源:Django 概述页面)。
Django 有主见吗?
Web 框架通常将自己称为“有主见”或“无主见”。
有主见框架是指对处理任何特定任务的“正确方法”有主见的框架。它们通常支持 *在特定领域内* 的快速开发(解决特定类型的问题),因为做任何事情的正确方法通常是众所周知且有据可查的。但是,它们在解决其主要领域之外的问题时可能不太灵活,并且往往为可以使用哪些组件和方法提供了更少的选择。
相比之下,无主见框架对将组件组合在一起以实现目标的最佳方法,甚至对应该使用哪些组件,都有更少的限制。它们使开发人员更容易使用最合适的工具来完成特定任务,但代价是您需要自己找到这些组件。
Django 是“有点有主见”,因此它提供了“两全其美”。它提供了一组组件来处理大多数 Web 开发任务,以及一种(或两种)首选的使用方式。但是,Django 的解耦架构意味着您通常可以从许多不同的选项中进行选择,或者根据需要添加对全新选项的支持。
Django 代码是什么样子的?
在传统的以数据为中心的网站中,Web 应用程序会等待来自 Web 浏览器(或其他客户端)的 HTTP 请求。当收到请求时,应用程序会根据 URL 和可能在 POST
数据或 GET
数据中的信息来确定需要什么。根据需要,它可能会从数据库读取或写入信息,或执行满足请求所需的其他任务。然后,应用程序将向 Web 浏览器返回响应,通常通过将检索到的数据插入 HTML 模板中的占位符来动态创建 HTML 页面供浏览器显示。
Django Web 应用程序通常将处理每个步骤的代码分组到单独的文件中
- URLs:虽然可以通过单个函数处理来自每个 URL 的请求,但为每个资源编写一个单独的视图函数更易于维护。URL 映射器用于根据请求 URL 将 HTTP 请求重定向到相应的视图。URL 映射器还可以匹配 URL 中出现的特定字符串或数字模式,并将它们作为数据传递给视图函数。
- 视图:视图是一个请求处理程序函数,它接收 HTTP 请求并返回 HTTP 响应。视图通过 *模型* 访问满足请求所需的数据,并将响应的格式化委托给 *模板*。
- 模型:模型是定义应用程序数据结构的 Python 对象,并提供用于管理(添加、修改、删除)和查询数据库中的记录的机制。
- 模板:模板是一个文本文件,定义文件(如 HTML 页面)的结构或布局,其中使用占位符来表示实际内容。*视图* 可以使用 HTML 模板动态创建 HTML 页面,并使用来自 *模型* 的数据填充它。模板可以用于定义任何类型的文件的结构;它不必是 HTML!
注意:Django 将此组织称为“模型视图模板 (MVT)”架构。它与更常见的 模型视图控制器 架构有许多相似之处。
下面的部分将让您了解 Django 应用程序的这些主要部分是什么样子的(我们将在课程的后面详细介绍,在我们设置了开发环境之后)。
将请求发送到正确的视图 (urls.py)
URL 映射器通常存储在一个名为 urls.py 的文件中。在下面的示例中,映射器 (urlpatterns
) 定义了一个 *路由*(特定 URL *模式*)与对应视图函数之间的映射列表。如果收到一个 URL 与指定模式匹配的 HTTP 请求,则将调用关联的视图函数并将请求传递给它。
urlpatterns = [
path('admin/', admin.site.urls),
path('book/<int:id>/', views.book_detail, name='book_detail'),
path('catalog/', include('catalog.urls')),
re_path(r'^([0-9]+)/$', views.best),
]
urlpatterns
对象是一个由 path()
和/或 re_path()
函数组成的列表(Python 列表使用方括号定义,其中项用逗号分隔,并且可以有 可选的尾部逗号。例如:[item1, item2, item3,]
)。
两种方法的第一个参数都是一个将要匹配的路由(模式)。path()
方法使用尖括号定义将被捕获并作为命名参数传递给视图函数的 URL 部分。re_path()
函数使用一种灵活的模式匹配方法,称为正则表达式。我们将在后面的文章中讨论这些内容!
第二个参数是另一个函数,当模式匹配时将调用该函数。views.book_detail
表示该函数名为 book_detail()
,可以在名为 views
的模块中找到(即在一个名为 views.py
的文件中)。
处理请求 (views.py)
视图是 Web 应用程序的核心,接收来自 Web 客户端的 HTTP 请求并返回 HTTP 响应。在这两者之间,它们会协调框架的其他资源以访问数据库、渲染模板等。
下面的示例展示了一个最小的视图函数 index()
,它可以由我们在上一节中提到的 URL 映射器调用。与所有视图函数一样,它接收一个 HttpRequest
对象作为参数 (request
) 并返回一个 HttpResponse
对象。在这种情况下,我们不会对请求做任何操作,我们的响应会返回一个硬编码的字符串。我们将在后面的章节中展示一个做更多有趣事情的请求。
# filename: views.py (Django view functions)
from django.http import HttpResponse
def index(request):
# Get an HttpRequest - the request parameter
# perform operations using information from the request.
# Return HttpResponse
return HttpResponse('Hello from Django!')
注意: 一点 Python
- Python 模块 是存储在单独文件中的函数“库”,我们可能希望在代码中使用它们。这里,我们只从
django.http
模块中导入HttpResponse
对象,以便我们可以在视图中使用它:from django.http import HttpResponse
。还有其他方法可以导入模块中的一些或所有对象。 - 函数使用
def
关键字声明,如上所示,在函数名后面用括号列出命名参数;整行以冒号结尾。注意下一行都是缩进的。缩进非常重要,因为它指定代码行在特定代码块中(强制缩进是 Python 的一个关键特性,也是 Python 代码易读的原因之一)。
视图通常存储在一个名为 views.py 的文件中。
定义数据模型 (models.py)
Django Web 应用程序通过称为模型的 Python 对象管理和查询数据。模型定义存储数据的结构,包括字段类型,可能还包括其最大大小、默认值、选择列表选项、文档的帮助文本、表单的标签文本等。模型的定义独立于底层数据库——您可以选择多个数据库作为项目设置的一部分。一旦您选择要使用的数据库,您就不需要直接与它进行交互——您只需编写模型结构和其他代码,Django 就会为您处理所有与数据库通信的“脏活”。
下面的代码片段展示了一个非常简单的 Django 模型,用于 Team
对象。Team
类是从 Django 类 models.Model
派生的。它定义了团队名称和团队级别为字符字段,并指定了要为每个记录存储的字符的最大数量。team_level
可以是多个值之一,因此我们将其定义为选择字段,并提供要在显示时选择的映射以及要存储的数据,以及默认值。
# filename: models.py
from django.db import models
class Team(models.Model):
team_name = models.CharField(max_length=40)
TEAM_LEVELS = (
('U09', 'Under 09s'),
('U10', 'Under 10s'),
('U11', 'Under 11s'),
# …
# list other team levels
)
team_level = models.CharField(max_length=3, choices=TEAM_LEVELS, default='U11')
注意: 一点 Python
Python 支持“面向对象编程”,这种编程风格将代码组织成对象,对象包含相关数据以及用于操作这些数据的函数。对象也可以从其他对象继承/扩展/派生,允许在相关对象之间共享通用行为。在 Python 中,我们使用关键字 class
定义对象的“蓝图”。我们可以根据类中的模型创建多个特定类型的对象实例。
例如,这里我们有一个 Team
类,它从 Model
类派生。这意味着它是一个模型,将包含模型的所有方法,但我们也可以为它提供自己的专门特性。在我们的模型中,我们定义了数据库需要存储数据的字段,并为它们指定了特定的名称。Django 使用这些定义(包括字段名)来创建底层数据库。
查询数据 (views.py)
Django 模型提供了一个简单的查询 API 用于搜索关联的数据库。这可以匹配多个字段,使用不同的条件(例如,精确匹配、不区分大小写、大于等),并且可以支持复杂的语句(例如,您可以指定对 U11 团队的搜索,这些团队的团队名称以“Fr”开头或以“al”结尾)。
代码片段展示了一个用于显示我们所有 U09 团队的视图函数(资源处理程序)。list_teams = Team.objects.filter(team_level__exact="U09")
行展示了如何使用模型查询 API 过滤所有 team_level
字段的值恰好为 'U09
' 的记录(注意这个条件是如何作为参数传递给 filter()
函数的,字段名和匹配类型用双下划线分隔:team_level__exact
)。
## filename: views.py
from django.shortcuts import render
from .models import Team
def index(request):
list_teams = Team.objects.filter(team_level__exact="U09")
context = {'youngest_teams': list_teams}
return render(request, '/best/index.html', context)
该函数使用 render()
函数创建发送回浏览器的 HttpResponse
。这个函数是一个快捷方式;它通过组合指定的 HTML 模板和一些要插入模板的数据(在名为“context
”的变量中提供)来创建一个 HTML 文件。在下一节中,我们将展示如何将数据插入模板以创建 HTML。
渲染数据 (HTML 模板)
模板系统允许您指定输出文档的结构,使用占位符来代替生成页面时将填充的数据。模板通常用于创建 HTML,但也可以创建其他类型的文档。Django 默认情况下支持自己的模板系统以及另一个流行的 Python 库 Jinja2(如果需要,它也可以支持其他系统)。
代码片段展示了上一节中 render()
函数调用的 HTML 模板可能是什么样子。这个模板是在假设它在渲染时可以访问一个名为 youngest_teams
的列表变量的情况下编写的(这包含在上面的 render()
函数中的 context
变量中)。在 HTML 骨架中,我们有一个表达式,它首先检查 youngest_teams
变量是否存在,然后在 for
循环中迭代它。在每次迭代中,模板都会在
元素中显示每个团队的 <li>
team_name
值。
## filename: best/templates/best/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home page</title>
</head>
<body>
{% if youngest_teams %}
<ul>
{% for team in youngest_teams %}
<li>{{ team.team_name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No teams are available.</p>
{% endif %}
</body>
</html>
你还能做什么?
前面的部分展示了您几乎在每个 Web 应用程序中都会使用的主要功能:URL 映射、视图、模型和模板。Django 提供的其他功能还包括
- 表单:HTML 表单用于收集用户数据以便在服务器上进行处理。Django 简化了表单创建、验证和处理。
- 用户身份验证和权限:Django 包含一个强大的用户身份验证和权限系统,该系统是秉承安全理念构建的。
- 缓存:动态创建内容比提供静态内容要消耗更多的计算资源(更慢)。Django 提供灵活的缓存,因此您可以存储渲染页面中的全部或部分内容,这样只有在必要时才会重新渲染。
- 管理站点:当您使用基本骨架创建应用程序时,Django 管理站点默认情况下会包含在内。它可以轻松地为网站管理员提供一个管理页面,用于创建、编辑和查看网站中的任何数据模型。
- 序列化数据:Django 使序列化和以 XML 或 JSON 格式提供数据变得轻而易举。这在创建 Web 服务(一个纯粹提供数据的网站,供其他应用程序或网站使用,自身不显示任何内容)或在创建客户端代码处理所有数据渲染的网站时很有用。