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,因为系统上禁用运行脚本。错误会提供有关如何允许运行脚本的信息链接。否则,请使用“终端: 选择默认配置文件”将“Command Prompt”或“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
运行项目的管理命令。[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 终端输出窗口也会显示服务器日志。 -
完成后,关闭浏览器窗口,并按照终端输出窗口中的指示,使用Ctrl+C 停止 VS Code 中的服务器。
创建 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
相同。(如果需要,可以将端口号(例如"5000"
)添加到args
中。)"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 = "
,然后将 Hello there, " + clean_name + "
"content
中的结果直接提供给浏览器。这种做法允许攻击者在 URL 中放置恶意 HTML(包括 JavaScript 代码),这些 HTML 最终会进入 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”,它们由一对花括号{{
和}}
分隔。所有其他不变文本都是模板的一部分,以及格式标记(例如)。如你所见,模板占位符还可以包含格式设置,即竖线
|
符号后面的表达式,在此示例中使用了 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() } )
可以看到,代码现在简单得多,只关注数据值,因为标记和格式化都包含在模板中。
-
启动程序(在调试器内部或外部,使用 ⌃F5 (Windows、Linux Ctrl+F5)),导航到 /hello/name URL,并观察结果。
-
还尝试导航到 /hello/name URL,使用类似
<a%20value%20that%20could%20be%20HTML>
的名称,以查看 Django 的自动转义如何工作。名称值在浏览器中显示为纯文本,而不是渲染为一个实际元素。
提供静态文件
静态文件是你的 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 标记,其内容预期由扩展模板覆盖。在基础模板和扩展模板中,block 标记由 {% block <name> %}
和 {% endblock %}
划定。
以下步骤演示了如何创建基础模板。
-
在
templates/hello
文件夹中,创建一个名为layout.html
的文件,其内容如下,其中包含名为“title”和“content”的 block。如你所见,标记定义了一个简单的导航栏结构,其中包含指向主页、关于和联系页面的链接,这些页面将在后面的部分创建。注意使用 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>
-
在现有的“message”样式下方,将以下样式添加到
static/hello/site.css
中,并保存文件。(本教程不尝试演示响应式设计;这些样式只是生成一个相当有趣的结果。).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 都会将片段作为自动完成选项提供,如下一节所示。你还可以使用“插入片段”命令从菜单中选择片段。
有关代码片段的更多信息,请参阅 创建片段。
使用代码片段添加页面
有了代码片段,你可以快速为 Home、About 和 Contact 页面创建模板。
-
在
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>
,然后保存文件。 -
重复上一步,使用
Contact us
和<p>Contact page for the Visual Studio Code Django tutorial.</p>
创建templates/hello/contact.html
。 -
在应用的
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 browser 等工具直接使用数据库。使用此类工具添加或删除表中的记录是可以的,但请避免更改数据库架构,因为这样数据库将与你的应用模型不同步。相反,请更改模型,运行 makemigrations
,然后运行 migrate
。
数据库类型
默认情况下,Django 包含一个 db.sqlite3
文件作为应用数据库,适用于开发工作。正如 何时使用 SQLite (sqlite.org) 中所述,SQLite 对于每天访问量低于 100K 的中低流量网站来说非常适合,但不建议用于更高流量的网站。它也仅限于单台计算机,因此不能用于任何多服务器场景,例如负载均衡和地理复制。
出于这些原因,请考虑使用生产级别的数据库,例如 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 情况(if 条件)下,它从表单中检索数据到数据对象 (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
中,用派生自ListView
的名为HomeListView
的类替换home
函数,该类将自身与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>
等行。 -
你还可以在“调试控制台”面板中处理变量。(但是,目前在控制台中无法使用 Django 过滤器,例如
date
。) -
准备就绪后,选择“继续”(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 命令文档中的 Requirements Files。
创建超级用户并启用管理界面
默认情况下,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 管理站点文档。
使用 Docker 扩展为 Django 应用创建容器
Docker 扩展 可轻松地从 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 相关的以下文章