在 Visual Studio Code 中使用 Django 的教程
Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 为 URL 路由、页面模板和处理数据提供了丰富的支持。
在这个 Django 教程中,您将创建一个简单的 Django 应用程序,该应用程序有三个页面,使用一个通用的基础模板。您将在 Visual Studio Code 的环境中创建此应用程序,以了解如何在 VS Code 终端、编辑器和调试器中与 Django 协同工作。本教程不会探讨 Django 本身的各种细节,例如处理数据模型和创建管理界面。有关这些方面的指导,请参阅本教程末尾的 Django 文档链接。
本 Django 教程的完整代码项目可以在 GitHub 上找到:python-sample-vscode-django-tutorial。
如果你有任何问题,可以在 Python 扩展讨论问答中搜索答案或提问。
先决条件
要成功完成此 Django 教程,您必须执行以下操作(这些步骤与通用 Python 教程中的步骤相同):
-
安装 Python 扩展。
-
安装 Python 3 的一个版本(本教程是为此版本编写的)。选项包括:
- (所有操作系统)从 python.org 下载;通常使用页面上首先出现的 Download Python 3.9.1 按钮(或任何最新版本)。
- (Linux)内置的 Python 3 安装可以很好地工作,但要安装其他 Python 包,您必须在终端中运行
sudo apt install python3-pip
。 - (macOS)通过 macOS 上的 Homebrew 使用
brew install python3
进行安装(不支持 macOS 上的系统 Python 安装)。 - (所有操作系统)从 Anaconda 下载(用于数据科学目的)。
-
在 Windows 上,请确保您的 Python 解释器的位置已包含在您的 PATH 环境变量中。您可以通过在命令提示符下运行
path
来检查该位置。如果 Python 解释器的文件夹未包含在内,请打开 Windows 设置,搜索“环境”,选择 为您的帐户编辑环境变量,然后编辑 Path 变量以包含该文件夹。
为 Django 教程创建一个项目环境
在本节中,您将创建一个安装了 Django 的虚拟环境。使用虚拟环境可以避免将 Django 安装到全局 Python 环境中,并让您精确控制应用程序中使用的库。虚拟环境还使得为环境创建 requirements.txt 文件变得容易。
-
在您的文件系统上,为本教程创建一个项目文件夹,例如
hello_django
。 -
在该文件夹中,使用以下命令(根据您的计算机选择)创建一个名为
.venv
的虚拟环境,该环境基于您当前的解释器:# Linux sudo apt-get install python3-venv # If needed python3 -m venv .venv source .venv/bin/activate # macOS python3 -m venv .venv source .venv/bin/activate # Windows py -3 -m venv .venv .venv\scripts\activate
注意:运行上述命令时,请使用标准的 Python 安装。如果您使用 Anaconda 安装中的
python.exe
,您会看到一个错误,因为 ensurepip 模块不可用,环境会处于未完成状态。 -
通过运行
code .
或运行 VS Code 并使用 文件 > 打开文件夹 命令,在 VS Code 中打开项目文件夹。 -
在 VS Code 中,打开命令面板(查看 > 命令面板 或 (Ctrl+Shift+P (macOS ⇧⌘P)))。然后选择 Python: Select Interpreter 命令:
-
该命令会显示 VS Code 可以自动定位的可用解释器列表(您的列表会有所不同;如果您没有看到所需的解释器,请参阅配置 Python 环境)。从列表中,选择项目文件夹中以
./.venv
或.\.venv
开头的虚拟环境: -
从命令面板运行 终端:创建新终端 (Ctrl+Shift+` (macOS ⌃⇧`)),这将创建一个终端并运行其激活脚本来自动激活虚拟环境。
注意:在 Windows 上,如果您的默认终端类型是 PowerShell,您可能会看到一个错误,提示无法运行 activate.ps1,因为系统上禁用了脚本运行。该错误提供了一个链接,说明如何允许脚本。否则,请使用 终端:选择默认配置文件 将“命令提示符”或“Git Bash”设置为您的默认终端。
-
所选环境显示在 VS Code 状态栏的右侧,并注意到 ('.venv': venv) 指示符,告诉您正在使用虚拟环境:
-
通过在 VS Code 终端中运行以下命令来更新虚拟环境中的 pip:
python -m pip install --upgrade pip
-
通过在 VS Code 终端中运行以下命令来在虚拟环境中安装 Django:
python -m pip install django
现在您有了一个自包含的环境,可以编写 Django 代码了。当您使用 终端:创建新终端 (Ctrl+Shift+` (macOS ⌃⇧`)) 时,VS Code 会自动激活该环境。如果您打开一个单独的命令提示符或终端,请通过运行 source .venv/bin/activate
(Linux/macOS) 或 .venv\Scripts\Activate.ps1
(Windows) 来激活环境。当命令提示符的开头显示 (.venv) 时,您就知道环境已被激活。
创建并运行一个最小的 Django 应用
在 Django 术语中,一个“Django 项目”由几个站点级别的配置文件以及一个或多个您部署到 Web 主机以创建完整 Web 应用程序的“应用”组成。一个 Django 项目可以包含多个应用,每个应用通常在项目中具有独立的功能,并且同一个应用可以存在于多个 Django 项目中。就其本身而言,应用只是一个遵循 Django 期望的某些约定的 Python 包。
因此,要创建一个最小的 Django 应用,首先需要创建 Django 项目作为应用的容器,然后再创建应用本身。对于这两个目的,您都使用 Django 管理实用程序 django-admin
,它在您安装 Django 包时就已经安装了。
创建 Django 项目
-
在已激活虚拟环境的 VS Code 终端中,运行以下命令:
django-admin startproject web_project .
这个
startproject
命令(通过末尾的.
)假定当前文件夹是您的项目文件夹,并在其中创建以下内容:-
manage.py
:项目的 Django 命令行管理实用程序。您使用python manage.py <command> [options]
来为项目运行管理命令。 -
一个名为
web_project
的子文件夹,其中包含以下文件:__init__.py
:一个空文件,告诉 Python 该文件夹是一个 Python 包。asgi.py
:一个用于 ASGI 兼容 的 Web 服务器为您的项目提供服务的入口点。您通常会保持此文件原样,因为它为生产 Web 服务器提供了钩子。settings.py
:包含 Django 项目的设置,您在开发 Web 应用的过程中会修改这些设置。urls.py
:包含 Django 项目的目录,您在开发过程中也会修改它。wsgi.py
:一个用于 WSGI 兼容的 Web 服务器为您的项目提供服务的入口点。您通常会保持此文件原样,因为它为生产 Web 服务器提供了钩子。
-
-
通过运行以下命令创建一个空的开发数据库:
python manage.py migrate
当您第一次运行服务器时,它会在文件
db.sqlite3
中创建一个默认的 SQLite 数据库,该数据库用于开发目的,但也可用于低流量 Web 应用的生产环境。有关数据库的更多信息,请参阅数据库类型部分。 -
要验证 Django 项目,请确保您的虚拟环境已激活,然后使用命令
python manage.py runserver
启动 Django 的开发服务器。服务器在默认端口 8000 上运行,您会在终端窗口中看到类似以下的输出:Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). June 13, 2023 - 18:38:07 Django version 4.2.2, using settings 'web_project.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.
Django 的内置 Web 服务器仅用于本地开发。但是,当您部署到 Web 主机时,Django 会使用主机的 Web 服务器。Django 项目中的
wsgi.py
和asgi.py
模块负责与生产服务器对接。如果您想使用非默认的 8000 端口,请在命令行中指定端口号,例如
python manage.py runserver 5000
。 -
在终端输出窗口中按住 Ctrl 并单击
http://127.0.0.1:8000/
URL,以在您的默认浏览器中打开该地址。如果 Django 安装正确且项目有效,您将看到如下所示的默认页面。VS Code 终端输出窗口还会显示服务器日志。 -
完成后,关闭浏览器窗口并在 VS Code 中使用 Ctrl+C 停止服务器,如终端输出窗口中所示。
创建一个 Django 应用
-
在已激活虚拟环境的 VS Code 终端中,在您的项目文件夹(
manage.py
所在的位置)中运行管理实用程序的startapp
命令:python manage.py startapp hello
该命令会创建一个名为
hello
的文件夹,其中包含许多代码文件和一个子文件夹。其中,您会经常使用views.py
(包含定义 Web 应用页面的函数)和models.py
(包含定义数据对象的类)。migrations
文件夹由 Django 的管理实用程序用于管理数据库版本,本教程稍后会讨论。还有apps.py
(应用配置)、admin.py
(用于创建管理界面)和tests.py
(用于创建测试)等文件,此处不作介绍。 -
修改
hello/views.py
以匹配以下代码,该代码为应用的主页创建一个视图:from django.http import HttpResponse def home(request): return HttpResponse("Hello, Django!")
-
创建一个文件
hello/urls.py
,内容如下。urls.py
文件是您指定模式以将不同 URL 路由到其相应视图的地方。下面的代码包含一个路由,将应用的根 URL (""
) 映射到您刚刚添加到hello/views.py
的views.home
函数:from django.urls import path from hello import views urlpatterns = [ path("", views.home, name="home"), ]
-
web_project
文件夹还包含一个urls.py
文件,这是实际处理 URL 路由的地方。打开web_project/urls.py
并将其修改为匹配以下代码(如果您愿意,可以保留指导性注释)。此代码使用django.urls.include
引入应用的hello/urls.py
,这使应用的路由包含在应用内部。当项目包含多个应用时,这种分离很有帮助。from django.contrib import admin from django.urls import include, path urlpatterns = [ path("", include("hello.urls")), path('admin/', admin.site.urls) ]
-
保存所有修改过的文件。
-
在 VS Code 终端中,再次激活虚拟环境,使用
python manage.py runserver
运行开发服务器,并打开浏览器访问http://127.0.0.1:8000/
,您将看到一个呈现“Hello, Django”的页面。
创建调试器启动配置文件
您可能已经想知道是否有一种更简单的方法来运行服务器和测试应用程序,而无需每次都输入 python manage.py runserver
。幸运的是,有的!您可以在 VS Code 中创建一个自定义的启动配置文件,该文件也用于不可避免的调试练习。
-
在 VS Code 中切换到 运行 视图(使用左侧活动栏或 F5)。您可能会看到消息“要自定义运行和调试,请创建 launch.json 文件”。这意味着您还没有一个包含调试配置的
launch.json
文件。如果您单击 创建 launch.json 文件 链接,VS Code 可以为您创建该文件: -
选择该链接,VS Code 将提示您选择一个调试配置。从下拉列表中选择 Django,VS Code 将使用 Django 运行配置填充一个新的
launch.json
文件。launch.json
文件包含许多调试配置,每个配置都是configuration
数组中的一个独立的 JSON 对象。 -
向下滚动并检查名为“Python: Django”的配置:
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Python Debugger: Django", "type": "debugpy", "request": "launch", "program": "${workspaceFolder}\\manage.py", "args": ["runserver"], "django": true, "justMyCode": true } ] }
此配置告诉 VS Code 使用选定的 Python 解释器和
args
列表中的参数运行"${workspaceFolder}/manage.py"
。因此,使用此配置启动 VS Code 调试器与在已激活虚拟环境的 VS Code 终端中运行python manage.py runserver
是相同的。(如果需要,您可以向args
添加端口号,如"5000"
)。"django": true
条目还告诉 VS Code 启用 Django 页面模板的调试,您将在本教程后面看到这一点。 -
通过选择 运行 > 启动调试 菜单命令,或选择列表旁边的绿色 启动调试 箭头 (F5) 来测试配置。
-
在终端输出窗口中按住 Ctrl 并单击
http://127.0.0.1:8000/
URL,以在浏览器中打开并查看应用程序是否正常运行。 -
完成后,关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或 运行 > 停止调试 命令 (Shift+F5 (macOS ⇧F5))。
-
您现在可以随时使用 运行 > 启动调试 来测试应用程序,这还有一个好处,就是会自动保存所有修改过的文件。
探索调试器
调试使您有机会在特定的代码行暂停正在运行的程序。当程序暂停时,您可以检查变量,在“调试控制台”面板中运行代码,并利用 调试 中描述的其他功能。运行调试器还会在调试会话开始前自动保存任何已修改的文件。
开始之前:请确保您已在上一节末尾通过在终端中使用 Ctrl+C 停止了正在运行的应用程序。如果您将应用程序留在一个终端中运行,它将继续占用该端口。因此,当您在调试器中使用相同的端口运行应用程序时,原始正在运行的应用程序会处理所有请求,您将不会在正在调试的应用程序中看到任何活动,并且程序不会在断点处停止。换句话说,如果调试器似乎不起作用,请确保没有其他应用程序实例仍在运行。
-
在
hello/urls.py
中,向urlpatterns
列表添加一个路由:path("hello/<name>", views.hello_there, name="hello_there"),
path
的第一个参数定义了一个路由 "hello/",它接受一个名为 name 的变量字符串。该字符串将传递给path
的第二个参数中指定的views.hello_there
函数。URL 路由是区分大小写的。例如,路由
/hello/<name>
与/Hello/<name>
是不同的。如果您希望同一个视图函数处理这两种情况,请为每个变体定义路径。 -
将
views.py
的内容替换为以下代码,以定义您可以在调试器中单步执行的hello_there
函数:import re from django.utils.timezone import datetime from django.http import HttpResponse def home(request): return HttpResponse("Hello, Django!") def hello_there(request, name): now = datetime.now() formatted_now = now.strftime("%A, %d %B, %Y at %X") # Filter the name argument to letters only using regular expressions. URL arguments # can contain arbitrary text, so we restrict to safe characters only. match_object = re.match("[a-zA-Z]+", name) if match_object: clean_name = match_object.group(0) else: clean_name = "Friend" content = "Hello there, " + clean_name + "! It's " + formatted_now return HttpResponse(content)
在 URL 路由中定义的
name
变量作为参数传递给hello_there
函数。如代码注释中所述,始终过滤任意用户提供的信息,以避免对您的应用进行各种攻击。在这种情况下,代码将名称参数过滤为仅包含字母,从而避免注入控制字符、HTML 等。(当您在下一节中使用模板时,Django 会进行自动过滤,您就不需要这段代码了。) -
通过执行以下任一操作,在
hello_there
函数的第一行代码 (now = datetime.now()
) 处设置一个断点:- 将光标放在该行上,按 F9,或者,
- 将光标放在该行上,选择 运行 > 切换断点 菜单命令,或者,
- 直接单击行号左侧的边距(悬停时会出现一个褪色的红点)。
断点在左边距中显示为一个红点:
-
通过选择 运行 > 启动调试 菜单命令,或选择列表旁边的绿色 启动调试 箭头 (F5) 来启动调试器。
观察状态栏颜色变化以指示正在调试:
一个调试工具栏(如下所示)也会出现在 VS Code 中,按以下顺序包含命令:暂停(或继续,F5)、单步跳过(F10)、单步进入(F11)、单步跳出(Shift+F11 (macOS ⇧F11))、重启(Ctrl+Shift+F5 (macOS ⇧⌘F5))和停止(Shift+F5 (macOS ⇧F5))。有关每个命令的说明,请参阅 VS Code 调试。
-
输出会出现在一个“Python 调试控制台”终端中。打开浏览器并导航到
http://127.0.0.1:8000/hello/VSCode
。在页面呈现之前,VS Code 会在您设置的断点处暂停程序。断点上的小黄箭头表示这是下一行要运行的代码。 -
使用“单步跳过”运行
now = datetime.now()
语句。 -
在 VS Code 窗口的左侧,您会看到一个 变量 窗格,显示本地变量,如
now
,以及参数,如name
。在其下方是 监视、调用堆栈 和 断点 的窗格(详情请见 VS Code 调试)。在 本地 部分,尝试展开不同的值。您还可以双击值(或使用 F2 (macOS Enter))来修改它们。然而,更改像now
这样的变量可能会破坏程序。开发人员通常只在代码没有产生正确值时进行更改以纠正值。 -
当程序暂停时,调试控制台 面板(与终端面板中的“Python 调试控制台”不同)可让您试验表达式,并使用程序的当前状态尝试运行代码片段。例如,一旦您单步跳过了
now = datetime.now()
这一行,您就可以试验不同的日期/时间格式。在编辑器中,选择读取now.strftime("%A, %d %B, %Y at %X")
的代码,然后右键单击并选择 调试:求值 以将该代码发送到调试控制台,并在那里运行它:now.strftime("%A, %d %B, %Y at %X") 'Friday, 07 September, 2018 at 07:46:32'
提示:调试控制台 还会显示应用内部可能不会出现在终端中的异常。例如,如果您在 运行和调试 视图的 调用堆栈 区域看到“在异常处暂停”的消息,请切换到 调试控制台 查看异常消息。
-
将该行复制到调试控制台底部的 > 提示符处,并尝试更改格式:
now.strftime("%A, %d %B, %Y at %X") 'Tuesday, 13 June, 2023 at 18:03:19' now.strftime("%a, %d %b, %Y at %X") 'Tue, 13 Jun, 2023 at 18:03:19' now.strftime("%a, %d %b, %y at %X") 'Tue, 13 Jun, 23 at 18:03:19'
-
如果您愿意,可以单步执行几行代码,然后选择“继续”(F5)让程序运行。浏览器窗口将显示结果:
-
修改代码中的那一行以使用不同的日期时间格式,例如
now.strftime("%a, %d %b, %y at %X")
,然后保存文件。Django 服务器将自动重新加载,这意味着更改将无需重启调试器即可应用。在浏览器中刷新页面以查看更新。 -
完成后,关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或 运行 > 停止调试 命令 (Shift+F5 (macOS ⇧F5))。
提示:为了更方便地重复导航到特定 URL,如
http://127.0.0.1:8000/hello/VSCode
,可以在views.py
等文件的某处使用
“转到定义”和“速览定义”命令
在您使用 Django 或任何其他库的过程中,您可能希望检查这些库本身的代码。VS Code 提供了两个方便的命令,可以直接导航到任何代码中类和其他对象的定义:
-
转到定义 从您的代码跳转到定义对象的代码。例如,在
views.py
中,右键单击home
函数中的HttpResponse
,然后选择 转到定义(或使用 F12),这将导航到 Django 库中的类定义。 -
速览定义 (Alt+F12 (macOS ⌥F12, Linux Ctrl+Shift+F10)),也在右键上下文菜单中),与前者类似,但直接在编辑器中显示类定义(在编辑器窗口中腾出空间以避免遮挡任何代码)。按 Escape 关闭速览窗口或使用右上角的 x。
使用模板渲染页面
到目前为止,您在本教程中创建的应用程序仅从 Python 代码生成纯文本网页。虽然可以直接在代码中生成 HTML,但开发人员避免这种做法,因为它会使应用程序遭受跨站脚本 (XSS) 攻击。例如,在本教程的 hello_there
函数中,有人可能会想在代码中使用类似 content = "<h1>Hello there, " + clean_name + "!</h1>"
的方式格式化输出,其中 content
中的结果直接提供给浏览器。这个漏洞允许攻击者在 URL 中放置恶意 HTML,包括 JavaScript 代码,这些代码最终会进入 clean_name
,从而在浏览器中运行。
一个更好的做法是完全将 HTML 从代码中分离出来,使用模板,这样您的代码只关心数据值,而不关心渲染。
在 Django 中,模板是一个 HTML 文件,其中包含代码在运行时提供的值的占位符。Django 模板引擎在渲染页面时负责进行替换,并提供自动转义以防止 XSS 攻击(也就是说,如果您尝试在数据值中使用 HTML,您只会看到 HTML 渲染为纯文本)。因此,代码只关心数据值,而模板只关心标记。Django 模板提供了灵活的选项,例如模板继承,它允许您定义一个带有通用标记的基础页面,然后在此基础上构建特定于页面的添加内容。
在本节中,您将首先使用模板创建一个单页。在后续部分中,您将配置应用以提供静态文件,然后为应用创建多个页面,每个页面都包含一个来自基础模板的导航栏。Django 模板还支持控制流和迭代,正如您稍后在本教程中在模板调试的上下文中看到的那样。
-
在
web_project/settings.py
文件中,找到INSTALLED_APPS
列表并添加以下条目,以确保项目了解该应用,以便处理模板:'hello',
-
在
hello
文件夹内,创建一个名为templates
的文件夹,然后再创建一个名为hello
的子文件夹以匹配应用名称(这种两层文件夹结构是典型的 Django 约定)。 -
在
templates/hello
文件夹中,创建一个名为hello_there.html
的文件,内容如下。此模板包含两个名为 "name" 和 "date" 的数据值占位符,由成对的花括号{{
和}}
分隔。所有其他不变的文本都是模板的一部分,以及格式化标记(如<strong>
)。如您所见,模板占位符还可以包含格式化,即管道符|
后面的表达式,本例中使用了 Django 的内置日期过滤器和时间过滤器。因此,代码只需要传递日期时间值,而不是预先格式化好的字符串:<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Hello, Django</title> </head> <body> <strong>Hello there, {{ name }}!</strong> It's {{ date | date:"l, d F, Y" }} at {{ date | time:"H:i:s" }} </body> </html>
-
在
views.py
的顶部,添加以下 import 语句:from django.shortcuts import render
-
同样在
views.py
中,修改hello_there
函数以使用django.shortcuts.render
方法加载模板并提供模板上下文。上下文是在模板中使用的变量集。render
函数接受请求对象,后跟模板相对于templates
文件夹的路径,然后是上下文对象。(开发人员通常将模板命名为与使用它们的函数相同,但匹配的名称不是必需的,因为您总是在代码中引用确切的文件名。)def hello_there(request, name): print(request.build_absolute_uri()) #optional return render( request, 'hello/hello_there.html', { 'name': name, 'date': datetime.now() } )
您可以看到,代码现在变得简单得多,只关心数据值,因为标记和格式化都包含在模板中。
-
启动程序(在调试器内部或外部,使用 Ctrl+F5 (macOS ⌃F5)),导航到 /hello/name URL,并观察结果。
-
也可以尝试使用像
<a%20value%20that%20could%20be%20HTML>
这样的名称导航到 /hello/name URL,以查看 Django 的自动转义功能。“name”值在浏览器中显示为纯文本,而不是渲染成一个实际的元素。
提供静态文件
静态文件是您的 Web 应用为某些请求原样返回的内容片段,例如 CSS 文件。提供静态文件要求 settings.py
中的 INSTALLED_APPS
列表包含 django.contrib.staticfiles
,该项默认包含。
在 Django 中提供静态文件有点像一门艺术,尤其是在部署到生产环境时。这里展示的是一种简单的方法,适用于 Django 开发服务器和像 Gunicorn 这样的生产服务器。然而,对静态文件的全面处理超出了本教程的范围,因此更多信息,请参阅 Django 文档中的管理静态文件。
切换到生产环境时,导航到 `settings.py`,设置 `DEBUG=False`,并将 `ALLOWED_HOSTS = ['*']` 更改为允许特定的主机。在使用容器时,这可能会导致额外的工作。详情请见问题 13。
为静态文件准备应用
-
在项目的 `web_project/urls.py` 中,添加以下 `import` 语句:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
-
在同一个文件中,在末尾添加以下行,这会将标准的静态文件 URL 添加到项目识别的列表中:
urlpatterns += staticfiles_urlpatterns()
在模板中引用静态文件
-
在 `hello` 文件夹中,创建一个名为 `static` 的文件夹。
-
在 `static` 文件夹内,创建一个名为 `hello` 的子文件夹,与应用名称匹配。
这个额外的子文件夹的原因是,当您将 Django 项目部署到生产服务器时,您会将所有静态文件收集到一个文件夹中,然后由一个专用的静态文件服务器提供服务。`static/hello` 子文件夹确保当应用的静态文件被收集时,它们位于特定于应用的子文件夹中,并且不会与同一项目中的其他应用的文件发生冲突。
-
在 `static/hello` 文件夹中,创建一个名为 `site.css` 的文件,内容如下。输入此代码后,还请观察 VS Code 为 CSS 文件提供的语法高亮,包括颜色预览。
.message { font-weight: 600; color: blue; }
-
在
templates/hello/hello_there.html
中,在<title>
元素后添加以下几行。{% load static %}
标签是一个自定义的 Django 模板标签集,它允许您使用{% static %}
来引用像样式表这样的文件。{% load static %} <link rel="stylesheet" type="text/css" href="{% static 'hello/site.css' %}" />
-
同样在
templates/hello/hello_there.html
中,用以下使用message
样式的标记替换<body>
元素的内容,而不是<strong>
标签:<span class="message">Hello, there {{ name }}!</span> It's {{ date | date:'l, d F, Y' }} at {{ date | time:'H:i:s' }}.
-
运行应用,导航到 /hello/name URL,并观察消息以蓝色呈现。完成后停止应用。
使用 collectstatic 命令
对于生产部署,您通常使用 `python manage.py collectstatic` 命令将应用中的所有静态文件收集到一个文件夹中。然后,您可以使用一个专用的静态文件服务器来提供这些文件,这通常会带来更好的整体性能。以下步骤显示了如何进行此收集,尽管在 Django 开发服务器上运行时您不会使用此收集。
-
在
web_project/settings.py
中,添加以下行,定义使用collectstatic
命令时收集静态文件的位置:STATIC_ROOT = BASE_DIR / 'static_collected'
-
在终端中,运行命令
python manage.py collectstatic
,并观察到hello/site.css
被复制到与manage.py
同级的顶级static_collected
文件夹中。 -
在实践中,每当您更改静态文件并在部署到生产环境之前,都要运行 `collectstatic`。
创建多个继承自基础模板的模板
由于大多数 Web 应用程序都有不止一个页面,并且这些页面通常共享许多共同的元素,开发人员将这些共同的元素分离到一个基础页面模板中,然后其他页面模板再扩展它。(这也称为模板继承,意味着扩展的页面从基础页面继承元素。)
另外,因为您可能会创建许多扩展相同模板的页面,所以在 VS Code 中创建一个代码片段会很有帮助,通过它可以快速初始化新的页面模板。代码片段可以从单一来源提供一致的代码片段,从而避免因从现有代码中复制粘贴而可能引入的错误。
以下各节将逐步介绍此过程的不同部分。
创建基础页面模板和样式
Django 中的基础页面模板包含一组页面的所有共享部分,包括对 CSS 文件、脚本文件等的引用。基础模板还定义了一个或多个 block 标签,其内容期望被扩展模板覆盖。块标签在基础模板和扩展模板中都由 {% block <name> %}
和 {% endblock %}
界定。
以下步骤演示了如何创建基础模板。
-
在 `templates/hello` 文件夹中,创建一个名为 `layout.html` 的文件,内容如下,其中包含名为“title”和“content”的块。如您所见,标记定义了一个简单的导航栏结构,其中包含指向主页、关于和联系页面的链接,您将在后面的部分中创建这些页面。请注意使用 Django 的 `{% url %}` 标签通过相应 URL 模式的名称来引用其他页面,而不是通过相对路径。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>{% block title %}{% endblock %}</title> {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'hello/site.css' %}"/> </head> <body> <div class="navbar"> <a href="{% url 'home' %}" class="navbar-brand">Home</a> <a href="{% url 'about' %}" class="navbar-item">About</a> <a href="{% url 'contact' %}" class="navbar-item">Contact</a> </div> <div class="body-content"> {% block content %} {% endblock %} <hr/> <footer> <p>© 2018</p> </footer> </div> </body> </html>
-
将以下样式添加到 `static/hello/site.css` 中现有的“message”样式下方,并保存文件。(本演练不试图演示响应式设计;这些样式只是生成一个相当有趣的结果。)
.navbar { background-color: lightslategray; font-size: 1em; font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; color: white; padding: 8px 5px 8px 5px; } .navbar a { text-decoration: none; color: inherit; } .navbar-brand { font-size: 1.2em; font-weight: 600; } .navbar-item { font-variant: small-caps; margin-left: 30px; } .body-content { padding: 5px; font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
您可以在此时运行应用程序,但由于您没有在任何地方使用基础模板,也没有更改任何代码文件,因此结果与上一步相同。完成其余部分以查看最终效果。
创建代码片段
由于您将在下一节中创建的三个页面都扩展了 `layout.html`,因此创建一个**代码片段**来初始化一个带有对基础模板的适当引用的新模板文件可以节省时间。代码片段从单一来源提供了一段一致的代码,从而避免了在使用从现有代码复制粘贴时可能出现的错误。
-
在 VS Code 中,选择 文件 (Windows/Linux) 或 Code (macOS) 菜单,然后选择 首选项 > 用户代码片段。
-
在出现的列表中,选择 html。(如果您之前创建过代码片段,该选项可能会在列表的 现有代码片段 部分显示为“html.json”。)
-
在 VS Code 打开
html.json
后,在现有花括号内添加以下代码。(此处的解释性注释,未显示,描述了细节,例如$0
行如何指示 VS Code 在插入代码片段后放置光标的位置)"Django Tutorial: template extending layout.html": { "prefix": "djextlayout", "body": [ "{% extends \"hello/layout.html\" %}", "{% block title %}", "$0", "{% endblock %}", "{% block content %}", "{% endblock %}" ], "description": "Boilerplate template that extends layout.html" },
-
保存
html.json
文件(Ctrl+S (macOS ⌘S))。 -
现在,每当您开始输入代码片段的前缀时,例如 `djext`,VS Code 都会将该代码片段作为自动完成选项提供,如下一节所示。您也可以使用 插入代码片段 命令从菜单中选择一个代码片段。
有关代码片段的更多信息,请参阅创建代码片段。
使用代码片段添加页面
有了代码片段,您就可以快速创建主页、关于和联系页面的模板了。
-
在
templates/hello
文件夹中,创建一个名为home.html
的新文件,然后开始输入djext
,您会看到代码片段作为自动完成项出现:当您选择自动完成项时,代码片段的代码会出现,光标位于代码片段的插入点上:
-
在“title”块的插入点处,写入
Home
,在“content”块中,写入<p>Visual Studio Code Django 教程的主页。</p>
,然后保存文件。这些行是扩展页面模板中唯一独特的部分: -
在 `templates/hello` 文件夹中,创建 `about.html`,使用代码片段插入样板标记,在“title”和“content”块中分别插入 `关于我们` 和 `<p>Visual Studio Code Django 教程的关于页面。</p>`,然后保存文件。
-
重复上一步,创建 `templates/hello/contact.html`,使用 `联系我们` 和 `<p>Visual Studio Code Django 教程的联系页面。</p>`。
-
在应用的
urls.py
中,为 /about 和 /contact 页面添加路由。请注意,path
函数的name
参数定义了您在模板中用{% url %}
标签引用页面的名称。path("about/", views.about, name="about"), path("contact/", views.contact, name="contact"),
-
在 `views.py` 中,为 /about 和 /contact 路由添加函数,这些函数引用它们各自的页面模板。同时修改 `home` 函数以使用 `home.html` 模板。
# Replace the existing home function with the one below def home(request): return render(request, "hello/home.html") def about(request): return render(request, "hello/about.html") def contact(request): return render(request, "hello/contact.html")
运行应用
所有页面模板都已就位,保存 views.py
,运行应用,并在浏览器中打开主页以查看结果。在页面之间导航,以验证页面模板是否正确地扩展了基础模板。
处理数据、数据模型和迁移
许多 Web 应用程序处理存储在数据库中的信息,而 Django 通过使用模型,使得表示该数据库中的对象变得容易。在 Django 中,模型是一个 Python 类,派生自 django.db.models.Model
,它表示一个特定的数据库对象,通常是一个表。您将这些类放置在应用的 models.py
文件中。
使用 Django,您几乎完全通过在代码中定义的模型来与数据库交互。然后,随着您模型随时间的演变,Django 的“迁移”会自动处理底层数据库的所有细节。一般工作流程如下:
- 在您的
models.py
文件中对模型进行更改。 - 运行
python manage.py makemigrations
以在migrations
文件夹中生成脚本,将数据库从当前状态迁移到新状态。 - 运行
python manage.py migrate
将脚本应用到实际数据库。
迁移脚本有效地记录了您随着时间的推移对数据模型所做的所有增量更改。通过应用迁移,Django 会更新数据库以匹配您的模型。因为每个增量更改都有自己的脚本,所以 Django 可以自动将任何先前版本的数据库(包括新数据库)迁移到当前版本。因此,您只需要关心 models.py
中的模型,而无需关心底层的数据库模式或迁移脚本。让 Django 来做那部分工作吧!
在代码中,您也只使用模型类来存储和检索数据;Django 会处理底层的细节。唯一的例外是,您可以使用 Django 管理实用程序的 loaddata 命令将数据写入数据库。这个实用程序通常用于在 migrate
命令初始化模式后初始化一个数据集。
当使用 `db.sqlite3` 文件时,您也可以使用像 SQLite 浏览器 这样的工具直接与数据库交互。使用这样的工具在表中添加或删除记录是可以的,但要避免对数据库模式进行更改,因为那样数据库将与您的应用模型不同步。相反,应该更改模型,运行 `makemigrations`,然后运行 `migrate`。
数据库类型
默认情况下,Django 为应用程序的数据库包含一个 `db.sqlite3` 文件,该文件适合开发工作。正如 何时使用 SQLite (sqlite.org) 所述,SQLite 对于日访问量低于 10 万的中低流量站点工作良好,但不建议用于更高流量。它也仅限于单台计算机,因此不能用于任何多服务器场景,如负载均衡和地理复制。
出于这些原因,请考虑使用生产级数据存储,例如 PostgreSQL、MySQL 和 SQL Server。有关 Django 对其他数据库支持的信息,请参阅数据库设置。您还可以使用 适用于 Python 的 Azure SDK 来处理 Azure 存储服务,如表和 blob。
定义模型
Django 模型是一个派生自 django.db.model.Models
的 Python 类,您将其放置在应用的 models.py
文件中。在数据库中,每个模型都会自动获得一个名为 id
的唯一 ID 字段。所有其他字段都定义为类的属性,使用来自 django.db.models
的类型,例如 CharField
(有限文本)、TextField
(无限文本)、EmailField
、URLField
、IntegerField
、DecimalField
、BooleanField
、DateTimeField
、ForeignKey
和 ManyToMany
等。(有关详细信息,请参阅 Django 文档中的模型字段参考。)
每个字段都带有一些属性,比如 `max_length`。`blank=True` 属性表示该字段是可选的;`null=true` 表示一个值是可选的。还有一个 `choices` 属性,它将值限制在数据值/显示值元组数组中的值。
例如,在 `models.py` 中添加以下类,以定义一个数据模型,该模型表示简单消息日志中的带日期条目:
from django.db import models
from django.utils import timezone
class LogMessage(models.Model):
message = models.CharField(max_length=300)
log_date = models.DateTimeField("date logged")
def __str__(self):
"""Returns a string representation of a message."""
date = timezone.localtime(self.log_date)
return f"'{self.message}' logged on {date.strftime('%A, %d %B, %Y at %X')}"
模型类可以包含从其他类属性计算返回值的方法。模型通常包含一个 `__str__` 方法,该方法返回实例的字符串表示形式。
迁移数据库
由于您通过编辑 models.py
更改了数据模型,您需要更新数据库本身。在 VS Code 中,打开一个已激活虚拟环境的终端(使用 终端:创建新终端 命令,Ctrl+Shift+` (macOS ⌃⇧`)),导航到项目文件夹,并运行以下命令:
python manage.py makemigrations
python manage.py migrate
查看 `migrations` 文件夹,可以看到 `makemigrations` 生成的脚本。您也可以查看数据库本身,以确认模式已更新。
如果在运行命令时看到错误,请确保您没有使用之前步骤遗留的调试终端,因为它们可能没有激活虚拟环境。
通过模型使用数据库
在您的模型就位并且数据库迁移之后,您就可以只使用您的模型来存储和检索数据。在本节中,您将向应用程序添加一个表单页面,通过该页面您可以记录一条消息。然后,您将修改主页以显示这些消息。因为您在这里修改了许多代码文件,请注意细节。
-
在
hello
文件夹(您有views.py
的地方)中,创建一个名为forms.py
的新文件,代码如下,它定义了一个 Django 表单,其中包含一个从数据模型LogMessage
中提取的字段:from django import forms from hello.models import LogMessage class LogMessageForm(forms.ModelForm): class Meta: model = LogMessage fields = ("message",) # NOTE: the trailing comma is required
-
在
templates/hello
文件夹中,创建一个名为log_message.html
的新模板,内容如下,该模板假定被赋予一个名为form
的变量来定义表单的主体。然后它添加一个标签为“Log”的提交按钮。{% extends "hello/layout.html" %} {% block title %} Log a message {% endblock %} {% block content %} <form method="POST" class="log-form"> {% csrf_token %} {{ form.as_p }} <button type="submit" class="save btn btn-default">Log</button> </form> {% endblock %}
注意:Django 的
{% csrf_token %}
标签提供了对跨站请求伪造的保护。有关详细信息,请参阅 Django 文档中的跨站请求伪造保护。 -
在应用的 `static/hello/site.css` 文件中,添加一条规则使输入表单更宽:
input[name=message] { width: 80%; }
-
在应用的 `urls.py` 文件中,为新页面添加一个路由:
path("log/", views.log_message, name="log"),
-
在
views.py
中,定义名为log_message
的视图(由 URL 路由引用)。此视图处理 HTTP GET 和 POST 两种情况。在 GET 情况(else:
部分)中,它只显示您在前面步骤中定义的表单。在 POST 情况中,它从表单中检索数据到一个数据对象(message
),设置时间戳,然后保存该对象,此时它被写入数据库:# Add these to existing imports at the top of the file: from django.shortcuts import redirect from hello.forms import LogMessageForm from hello.models import LogMessage # Add this code elsewhere in the file: def log_message(request): form = LogMessageForm(request.POST or None) if request.method == "POST": if form.is_valid(): message = form.save(commit=False) message.log_date = datetime.now() message.save() return redirect("home") else: return render(request, "hello/log_message.html", {"form": form})
-
在您准备好尝试所有功能之前,还有一步!在
templates/hello/layout.html
中,在 "navbar" div 中为消息记录页面添加一个链接:<!-- Insert below the link to Home --> <a href="{% url 'log' %}" class="navbar-item">Log Message</a>
-
运行应用程序并打开浏览器到主页。在导航栏上选择 Log Message 链接,应该会显示消息记录页面:
-
输入一条消息,选择 Log,您应该会被带回主页。主页目前还没有显示任何已记录的消息(我们稍后会解决这个问题)。您可以随意多记录几条消息。如果您愿意,可以使用 SQLite Browser 等工具查看数据库,看看是否已创建记录。以只读方式打开数据库,或者记得在使用应用程序前关闭数据库,否则由于数据库被锁定,应用程序会失败。
-
完成后停止应用。
-
现在修改主页以显示已记录的消息。首先,用下面的标记替换应用 `templates/hello/home.html` 文件的内容。这个模板期望一个名为 `message_list` 的上下文变量。如果它收到了一个(用 `{% if message_list %}` 标签检查),它就会遍历那个列表(`{% for message in message_list %}` 标签)为每条消息生成表格行。否则页面会指示尚未记录任何消息。
{% extends "hello/layout.html" %} {% block title %} Home {% endblock %} {% block content %} <h2>Logged messages</h2> {% if message_list %} <table class="message_list"> <thead> <tr> <th>Date</th> <th>Time</th> <th>Message</th> </tr> </thead> <tbody> {% for message in message_list %} <tr> <td>{{ message.log_date | date:'d M Y' }}</td> <td>{{ message.log_date | time:'H:i:s' }}</td> <td> {{ message.message }} </td> </tr> {% endfor %} </tbody> </table> {% else %} <p>No messages have been logged. Use the <a href="{% url 'log' %}">Log Message form</a>.</p> {% endif %} {% endblock %}
-
在
static/hello/site.css
中,添加一条规则来稍微格式化一下表格:.message_list th,td { text-align: left; padding-right: 15px; }
-
在 `views.py` 中,导入 Django 的通用 `ListView` 类,我们将用它来实现主页:
from django.views.generic import ListView
-
同样在 `views.py` 中,用一个名为 `HomeListView` 的*类*替换 `home` 函数,该类派生自 `ListView`,它与 `LogMessage` 模型绑定,并实现一个 `get_context_data` 函数来为模板生成上下文。
# Remove the old home function if you want; it's no longer used class HomeListView(ListView): """Renders the home page, with a list of all messages.""" model = LogMessage def get_context_data(self, **kwargs): context = super(HomeListView, self).get_context_data(**kwargs) return context
-
在应用的 `urls.py` 中,导入数据模型:
from hello.models import LogMessage
-
同样在
urls.py
中,为新视图创建一个变量,该视图按降序检索最近的五个LogMessage
对象(这意味着它查询数据库),然后为模板上下文中的数据提供一个名称(message_list
),并标识要使用的模板:home_list_view = views.HomeListView.as_view( queryset=LogMessage.objects.order_by("-log_date")[:5], # :5 limits the results to the five most recent context_object_name="message_list", template_name="hello/home.html", )
-
在 `urls.py` 中,修改主页的路径以使用 `home_list_view` 变量:
# Replace the existing path for "" path("", home_list_view, name="home"),
-
启动应用并打开浏览器到主页,现在应该会显示消息:
-
完成后停止应用。
在页面模板中使用调试器
如上一节所示,页面模板可以包含过程性指令,如 {% for message in message_list %}
和 {% if message_list %}
,而不仅仅是被动的、声明性的元素,如 {% url %}
和 {% block %}
。因此,与任何其他过程性代码一样,模板内部也可能出现编程错误。
幸运的是,当您在调试配置中设置了 "django": true
(您已经这样做了)时,VS Code 的 Python 扩展提供了模板调试功能。以下步骤演示了此功能:
-
在
templates/hello/home.html
中,在{% if message_list %}
和{% for message in message_list %}
两行上设置断点,如下图中黄色箭头所示: -
在调试器中运行应用,并打开浏览器到主页。(如果您已经在运行调试器,设置断点后无需重启应用;只需刷新页面即可。)观察 VS Code 在模板的 `{% if %}` 语句处进入调试器,并在 变量 窗格中显示所有上下文变量:
-
使用“单步跳过”(F10) 命令来单步执行模板代码。观察到调试器会跳过所有声明性语句,并在任何过程性代码处暂停。例如,单步执行
{% for message in message_list %}
循环可以让您检查message
中的每个值,并让您单步到像<td>{{ message.log_date | date:'d M Y' }}</td>
这样的行。 -
您也可以在 调试控制台 面板中处理变量。(然而,像 `date` 这样的 Django 过滤器目前在控制台中不可用。)
-
准备就绪后,选择“继续”(F5) 以完成应用程序的运行并在浏览器中查看渲染的页面。完成后停止调试器。
可选活动
以下各节描述了您在使用 Python 和 Visual Studio Code 时可能会觉得有帮助的其他步骤。
为环境创建一个 requirements.txt 文件
当您通过源代码控制或其他方式共享您的应用代码时,复制虚拟环境中的所有文件是没有意义的,因为接收者总是可以自己重新创建该环境。
因此,开发人员通常会从源代码控制中省略虚拟环境文件夹,而是使用 `requirements.txt` 文件来描述应用的依赖项。
虽然您可以手动创建该文件,但您也可以使用 `pip freeze` 命令根据已激活环境中安装的确切库来生成该文件:
-
在使用 Python: Select Interpreter 命令选择您选择的环境后,运行 终端:创建新终端 命令 (Ctrl+Shift+` (macOS ⌃⇧`)) 以打开一个已激活该环境的终端。
-
在终端中,运行
pip freeze > requirements.txt
在您的项目文件夹中创建requirements.txt
文件。
任何接收项目副本的人(或任何构建服务器)只需运行 pip install -r requirements.txt
命令,即可在活动环境中重新安装应用所依赖的包。
注意:`pip freeze` 会列出您在当前环境中安装的所有 Python 包,包括您当前未使用的包。该命令还会列出带有确切版本号的包,您可能希望将其转换为范围以获得未来的更大灵活性。有关更多信息,请参阅 pip 命令文档中的需求文件。
创建超级用户并启用管理界面
默认情况下,Django 为 Web 应用提供一个受身份验证保护的管理界面。该界面通过内置的 `django.contrib.admin` 应用实现,该应用默认包含在项目的 `INSTALLED_APPS` 列表(`settings.py`)中,身份验证则由内置的 `django.contrib.auth` 应用处理,该应用也默认在 `INSTALLED_APPS` 中。
执行以下步骤以启用管理界面:
-
在应用中创建一个超级用户帐户,方法是在 VS Code 中为您的虚拟环境打开一个终端,然后运行命令 `python manage.py createsuperuser --username=<username> --email=<email>`,当然,用您的个人信息替换 `<username>` 和 `<email>`。当您运行该命令时,Django 会提示您输入并确认您的密码。
请务必记住您的用户名和密码组合。这些是您用来向应用进行身份验证的凭据。
-
在项目级别的
urls.py
(本教程中为web_project/urls.py
)中添加以下 URL 路由,以指向内置的管理界面:# This path is included by default when creating the app path("admin/", admin.site.urls),
-
运行服务器,然后打开浏览器访问应用的 /admin 页面(例如,使用开发服务器时为
http://127.0.0.1:8000/admin
)。 -
一个登录页面会出现,由 `django.contrib.auth` 提供。输入您的超级用户凭据。
-
一旦您通过身份验证,您将看到默认的管理页面,通过该页面您可以管理用户和组:
您可以根据自己的喜好自定义管理界面。例如,您可以提供编辑和删除数据库中条目的功能。有关进行自定义的更多信息,请参阅 Django 管理站点文档。
使用容器工具扩展为 Django 应用创建容器
容器工具扩展使得从 Visual Studio Code 构建、管理和部署容器化应用程序变得容易。如果您有兴趣学习如何为本教程中开发的 Django 应用创建 Python 容器,请查看容器中的 Python 教程,它将引导您完成如何:
- 创建一个描述简单 Python 容器的
Dockerfile
文件。 - 构建、运行并验证 Django 应用的功能。
- 调试在容器中运行的应用程序。
后续步骤
恭喜您完成了在 Visual Studio Code 中使用 Django 的本教程!
本教程的完整代码项目可以在 GitHub 上找到:python-sample-vscode-django-tutorial。
在本教程中,我们仅仅触及了 Django 所有功能的皮毛。请务必访问 Django 文档和官方 Django 教程,以获取有关视图、模板、数据模型、URL 路由、管理界面、使用其他类型的数据库、部署到生产环境等更多详细信息。
要在一个生产网站上试用您的应用,请查看教程使用 Docker 容器将 Python 应用部署到 Azure App Service。Azure 还提供一个标准容器,即 Linux 上的 App Service,您可以从 VS Code 中向其部署 Web 应用。
您可能还想查看 VS Code 文档中与 Python 相关的以下文章: