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 中,打开命令面板(查看 > 命令面板 或 (⇧⌘P (Windows, Linux Ctrl+Shift+P)))。然后选择 Python: Select Interpreter 命令:
-
该命令会显示 VS Code 可以自动定位的可用解释器列表(你的列表会有所不同;如果你没有看到所需的解释器,请参阅配置 Python 环境)。从列表中,选择你项目文件夹中以
./.venv
或.\.venv
开头的虚拟环境: -
从命令面板运行 终端:创建新终端 (⌃⇧` (Windows, Linux Ctrl+Shift+`)),这将创建一个终端并通过运行其激活脚本来自动激活虚拟环境。
注意:在 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 代码的环境。当你使用 终端:创建新终端 (⌃⇧` (Windows, Linux Ctrl+Shift+`)) 时,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,以在浏览器中打开,并看到应用正在正常运行。 -
完成后,关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或运行 > 停止调试命令 (⇧F5 (Windows, Linux Shift+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
函数。如代码注释中所述,始终要过滤任意用户提供的信息,以避免对你的应用进行各种攻击。在这种情况下,代码将 name 参数过滤为只包含字母,从而避免注入控制字符、HTML 等。(当你在下一节中使用模板时,Django 会进行自动过滤,你就不需要这段代码了。) -
通过执行以下任一操作,在
hello_there
函数的第一行代码 (now = datetime.now()
) 处设置一个断点:- 将光标放在该行上,按 F9,或者,
- 将光标放在该行上,选择运行 > 切换断点菜单命令,或者,
- 直接点击行号左侧的空白处(悬停时会出现一个褪色的红点)。
断点在左侧空白处显示为一个红点:
-
通过选择运行 > 启动调试菜单命令,或选择列表旁边的绿色启动调试箭头 (F5) 来启动调试器:
观察状态栏颜色变化,表示正在调试:
VS Code 中还会出现一个调试工具栏(如下所示),其中包含以下顺序的命令:暂停(或继续,F5)、单步跳过(F10)、单步进入(F11)、单步跳出(⇧F11 (Windows, Linux Shift+F11))、重启(⇧⌘F5 (Windows, Linux Ctrl+Shift+F5))和停止(⇧F5 (Windows, Linux Shift+F5))。有关每个命令的说明,请参见 VS Code 调试。
-
输出会出现在一个“Python 调试控制台”终端中。打开浏览器并导航到
http://127.0.0.1:8000/hello/VSCode
。在页面渲染之前,VS Code 会在你设置的断点处暂停程序。断点上的黄色小箭头表示这是下一行要运行的代码。 -
使用“单步跳过”来运行
now = datetime.now()
语句。 -
在 VS Code 窗口的左侧,你会看到一个变量窗格,显示局部变量(如
now
)以及参数(如name
)。其下方是监视、调用堆栈和断点窗格(详情请参阅 VS Code 调试)。在局部变量部分,尝试展开不同的值。你也可以双击值(或使用 Enter (Windows, Linux F2))来修改它们。然而,更改像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 服务器将自动重新加载,这意味着更改将无需重启调试器即可应用。刷新浏览器页面以查看更新。 -
完成后,关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或运行 > 停止调试命令 (⇧F5 (Windows, Linux Shift+F5))。
提示:为了更容易地重复导航到特定 URL,如
http://127.0.0.1:8000/hello/VSCode
,可以在像views.py
这样的文件中使用
“转到定义”和“速览定义”命令
在您使用 Django 或任何其他库时,您可能希望检查这些库本身的代码。VS Code 提供了两个方便的命令,可以直接导航到任何代码中类和其他对象的定义:
-
转到定义 从您的代码跳转到定义对象的代码。例如,在
views.py
中,右键单击home
函数中的HttpResponse
并选择转到定义(或使用 F12),这将导航到 Django 库中的类定义。 -
速览定义 (⌥F12 (Windows Alt+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
的顶部,添加以下导入语句: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() } )
你可以看到代码现在简单多了,只关心数据值,因为标记和格式化都包含在模板中。
-
启动程序(在调试器内部或外部,使用 ⌃F5 (Windows, Linux Ctrl+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
中,将<body>
元素的内容替换为以下标记,该标记使用message
样式而不是<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 <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)或代码(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
文件 (⌘S (Windows, Linux Ctrl+S))。 -
现在,每当你开始输入代码片段的前缀,例如
djext
,VS Code 就会将该代码片段作为自动完成选项提供,如下一节所示。你还可以使用插入代码片段命令从菜单中选择一个代码片段。
有关代码片段的更多信息,请参阅创建代码片段。
使用代码片段添加页面
有了代码片段,你就可以快速为主页、关于页面和联系页面创建模板了。
-
在
templates/hello
文件夹中,创建一个名为home.html
的新文件,然后开始输入djext
,你会看到代码片段作为一个自动补全选项出现:当你选择该补全项时,代码片段的代码就会出现,光标会停留在代码片段的插入点上:
-
在“title”块的插入点处,写入
Home
,在“content”块中,写入<p>Home page for the Visual Studio Code Django tutorial.</p>
,然后保存文件。这些行是扩展页面模板中唯一的部分。 -
在
templates/hello
文件夹中,创建about.html
,使用代码片段插入样板标记,在“title”和“content”块中分别插入About us
和<p>About page for the Visual Studio Code Django tutorial.</p>
,然后保存文件。 -
重复上一步,创建
templates/hello/contact.html
,使用Contact us
和<p>Contact page for the Visual Studio Code Django tutorial.</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 对其他数据库支持的信息,请参阅数据库设置。你还可以使用 Azure SDK for Python 来操作 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 中,打开一个已激活虚拟环境的终端(使用终端:创建新终端命令,⌃⇧` (Windows, Linux Ctrl+Shift+`)),导航到项目文件夹,并运行以下命令:
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>
-
运行应用并在浏览器中打开主页。选择导航栏上的记录消息链接,应会显示消息记录页面:
-
输入一条消息,选择记录,你会被带回到主页。主页目前还没有显示任何已记录的消息(我们稍后会解决这个问题)。你也可以随时记录更多的消息。如果你愿意,可以使用像 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
中,将home
函数替换为一个名为HomeListView
的类,该类派生自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: 选择解释器 命令选择您想要的环境后,运行 终端: 创建新终端 命令 (⌃⇧` (Windows, Linux Ctrl+Shift+`)) 以打开一个已激活该环境的终端。
-
在终端中,运行
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 相关的以下文章: