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教程中的步骤相同):

  1. 安装 Python 扩展

  2. 安装一个Python 3的版本(本教程是为该版本编写的)。选项包括:

    • (All operating systems) A download from python.org; typically use the Download Python 3.9.1 button that appears first on the page (or whatever is the latest version).
    • (Linux) The built-in Python 3 installation works well, but to install other Python packages you must run sudo apt install python3-pip in the terminal.
    • (macOS) An installation through Homebrew on macOS using brew install python3 (the system install of Python on macOS is not supported).
    • (All operating systems) A download from Anaconda (for data science purposes).
  3. 在Windows上,确保您的Python解释器的位置包含在您的PATH环境变量中。您可以通过在命令提示符下运行path来检查位置。如果未包含Python解释器的文件夹,请打开Windows设置,搜索“环境”,选择为您的账户编辑环境变量,然后编辑Path变量以包含该文件夹。

为Django教程创建项目环境

在本节中,您将创建一个安装了Django的虚拟环境。使用虚拟环境可以避免将Django安装到全局Python环境中,并让您精确控制应用程序中使用的库。虚拟环境还使得为环境创建requirements.txt文件变得容易。

  1. 在您的文件系统上,为本教程创建一个项目文件夹,例如 hello_django

  2. 在该文件夹中,使用以下命令(根据您的计算机适当选择)以基于当前解释器创建一个名为 .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模块不可用,环境将处于未完成状态。

  3. 在VS Code中通过运行code .打开项目文件夹,或者通过运行VS Code并使用文件 > 打开文件夹命令。

  4. 在 VS Code 中,打开命令面板(查看 > 命令面板 或 (⇧⌘P (Windows, Linux Ctrl+Shift+P)))。然后选择 Python: 选择解释器 命令:

    Django教程:在VS Code中打开命令面板

  5. 该命令展示了VS Code可以自动定位的可用解释器列表(您的列表可能会有所不同;如果没有看到所需的解释器,请参阅配置Python环境)。从列表中,选择项目文件夹中以./.venv.\.venv开头的虚拟环境:

    Django教程:为Python选择虚拟环境

  6. 运行终端:创建新终端 (⌃⇧` (Windows, Linux Ctrl+Shift+`)) 从命令面板中,这将创建一个终端并自动通过运行其激活脚本来激活虚拟环境。

    注意: 在Windows上,如果你的默认终端类型是PowerShell,你可能会看到一个错误,提示无法运行activate.ps1,因为系统上禁用了运行脚本。该错误提供了一个链接,说明如何允许脚本运行。否则,使用终端:选择默认配置文件将“命令提示符”或“Git Bash”设置为默认终端。

  7. 选定的环境会显示在 VS Code 状态栏的右侧,并注意到 ('.venv': venv) 指示器,它告诉你正在使用虚拟环境:

    Django教程:在VS Code状态栏中显示选定的环境

  8. 在VS Code终端中运行以下命令来更新虚拟环境中的pip:

    python -m pip install --upgrade pip
    
  9. 在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项目”由几个站点级别的配置文件组成,以及一个或多个“应用程序”,你将它们部署到网络主机以创建一个完整的网络应用程序。一个Django项目可以包含多个应用程序,每个应用程序通常在项目中具有独立的功能,并且同一个应用程序可以存在于多个Django项目中。就应用程序本身而言,它只是一个遵循Django期望的某些约定的Python包。

要创建一个最小的Django应用程序,首先需要创建Django项目作为应用程序的容器,然后创建应用程序本身。对于这两个目的,您可以使用Django管理工具django-admin,该工具在安装Django包时已安装。

创建Django项目

  1. 在激活了虚拟环境的 VS Code 终端中,运行以下命令:

    django-admin startproject web_project .
    

    这个startproject命令假设(通过在末尾使用.)当前文件夹是您的项目文件夹,并在其中创建以下内容:

    • manage.py: 项目的Django命令行管理工具。您可以使用python manage.py [options]来运行项目的管理命令。

    • 一个名为web_project的子文件夹,其中包含以下文件:

      • __init__.py: an empty file that tells Python that this folder is a Python package.
      • asgi.py: an entry point for ASGI-compatible web servers to serve your project. You typically leave this file as-is as it provides the hooks for production web servers.
      • settings.py: contains settings for Django project, which you modify in the course of developing a web app.
      • urls.py: contains a table of contents for the Django project, which you also modify in the course of development.
      • wsgi.py: an entry point for WSGI-compatible web servers to serve your project. You typically leave this file as-is as it provides the hooks for production web servers.
  2. 通过运行以下命令创建一个空的开发数据库:

    python manage.py migrate
    

    当你第一次运行服务器时,它会在文件中创建一个默认的SQLite数据库db.sqlite3,该数据库用于开发目的,但也可以在生产环境中用于低流量的Web应用程序。有关数据库的更多信息,请参阅数据库类型部分。

  3. 要验证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.pyasgi.py模块负责连接到生产服务器。

    如果你想使用不同于默认8000的端口,请在命令行中指定端口号,例如python manage.py runserver 5000

  4. Ctrl+点击终端输出窗口中的http://127.0.0.1:8000/ URL,以在默认浏览器中打开该地址。如果Django安装正确且项目有效,您将看到如下所示的默认页面。VS Code终端输出窗口还会显示服务器日志。

    Django教程:空Django项目的默认视图

  5. 完成后,关闭浏览器窗口,并在VS Code中使用Ctrl+C停止服务器,如终端输出窗口所示。

创建一个Django应用

  1. 在VS Code终端中激活您的虚拟环境后,在您的项目文件夹中(manage.py所在的位置)运行管理工具的startapp命令:

    python manage.py startapp hello
    

    该命令创建一个名为hello的文件夹,其中包含多个代码文件和一个子文件夹。在这些文件中,您经常使用views.py(包含定义网页应用程序中页面的函数)和models.py(包含定义数据对象的类)。migrations文件夹由Django的管理工具用于管理数据库版本,如本教程后面所述。还有apps.py(应用程序配置)、admin.py(用于创建管理界面)和tests.py(用于创建测试)文件,这些文件在此不涉及。

  2. 修改 hello/views.py 以匹配以下代码,该代码为应用程序的主页创建了一个视图:

    from django.http import HttpResponse
    
    def home(request):
        return HttpResponse("Hello, Django!")
    
  3. 创建一个文件,hello/urls.py,内容如下。urls.py 文件是您指定模式以将不同的 URL 路由到其适当视图的地方。下面的代码包含一个路由,将应用程序的根 URL ("") 映射到您刚刚添加到 hello/views.pyviews.home 函数:

    from django.urls import path
    from hello import views
    
    urlpatterns = [
        path("", views.home, name="home"),
    ]
    
  4. 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)
    ]
    
  5. 保存所有修改过的文件。

  6. 在VS Code终端中,再次激活虚拟环境后,使用python manage.py runserver运行开发服务器,并在浏览器中打开http://127.0.0.1:8000/,您将看到一个显示“Hello, Django”的页面。

    Django教程:在浏览器中运行的基本Django应用程序

创建一个调试器启动配置文件

你可能已经在想,有没有一种更简单的方法来运行服务器和测试应用程序,而不需要每次都输入python manage.py runserver。幸运的是,确实有!你可以在VS Code中创建一个定制的启动配置文件,这也用于不可避免的调试练习。

  1. 切换到VS Code中的运行视图(使用左侧的活动栏或F5)。你可能会看到消息“要自定义运行和调试,请创建一个launch.json文件”。这意味着你还没有包含调试配置的launch.json文件。如果你点击创建一个launch.json文件链接,VS Code可以为你创建该文件:

    Django教程:调试面板的初始视图

  2. 选择链接,VS Code 将提示调试配置。从下拉菜单中选择Django,VS Code 将使用 Django 运行配置填充一个新的launch.json文件。launch.json文件包含许多调试配置,每个配置都是configuration数组中的一个单独的 JSON 对象。

  3. 向下滚动并检查名为“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 页面模板的调试,您将在本教程的后面部分看到。

  4. 通过选择运行 > 开始调试菜单命令,或选择列表旁边的绿色开始调试箭头(F5)来测试配置:

    Django教程:调试工具栏上的开始调试/继续箭头

  5. Ctrl+点击终端输出窗口中的http://127.0.0.1:8000/ URL以打开浏览器并查看应用程序是否正常运行。

  6. 完成后关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或运行 > 停止调试命令(⇧F5 (Windows, Linux Shift+F5))。

  7. 您现在可以随时使用运行 > 开始调试来测试应用程序,这还具有自动保存所有修改文件的优点。

探索调试器

调试使您有机会在特定代码行上暂停正在运行的程序。当程序暂停时,您可以检查变量,在调试控制台面板中运行代码,并利用调试中描述的功能。运行调试器还会在调试会话开始之前自动保存所有修改过的文件。

在开始之前:确保你已经通过使用终端中的Ctrl+C停止了上一节末尾运行的应用程序。如果你让应用程序在一个终端中继续运行,它会继续占用端口。因此,当你使用相同的端口在调试器中运行应用程序时,原始运行的应用程序会处理所有请求,你将看不到正在调试的应用程序中的任何活动,程序也不会在断点处停止。换句话说,如果调试器似乎没有工作,请确保没有其他应用程序实例仍在运行。

  1. hello/urls.py 中,向 urlpatterns 列表添加一个路由:

    path("hello/<name>", views.hello_there, name="hello_there"),
    

    path的第一个参数定义了一个路由"hello/",该路由接受一个名为name的变量字符串。该字符串被传递给path的第二个参数中指定的views.hello_there函数。

    URL路由是区分大小写的。例如,路由/hello//Hello/是不同的。如果你希望同一个视图函数处理两者,请为每个变体定义路径。

  2. 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会自动进行过滤,你不需要这段代码。)

  3. hello_there函数的第一行代码(now = datetime.now())处设置断点,可以通过以下任意一种方式实现:

    • With the cursor on that line, press F9, or,
    • With the cursor on that line, select the Run > Toggle Breakpoint menu command, or,
    • Click directly in the margin to the left of the line number (a faded red dot appears when hovering there).

    断点显示为左边距中的红点:

    Django教程:在hello_there函数的第一行设置的断点

  4. 通过选择运行 > 开始调试菜单命令,或选择列表旁边的绿色开始调试箭头(F5)来启动调试器:

    Django教程:调试工具栏上的开始调试/继续箭头

    请注意,状态栏会改变颜色以指示调试状态:

    Django教程:调试状态栏的外观

    调试工具栏(如下所示)也会出现在 VS Code 中,包含以下顺序的命令:暂停(或继续,F5),跳过(F10),步入(F11),步出(⇧F11 (Windows, Linux Shift+F11)),重启(⇧⌘F5 (Windows, Linux Ctrl+Shift+F5)),和停止(⇧F5 (Windows, Linux Shift+F5))。有关每个命令的描述,请参见VS Code 调试

    Django教程:VS Code调试工具栏

  5. 输出显示在“Python调试控制台”终端中。打开浏览器并导航到http://127.0.0.1:8000/hello/VSCode。在页面渲染之前,VS Code会在您设置的断点处暂停程序。断点上的小黄色箭头表示这是要运行的下一行代码。

    Django教程:VS Code在断点处暂停

  6. 使用“单步跳过”来运行now = datetime.now()语句。

  7. 在VS Code窗口的左侧,您会看到一个变量窗格,显示局部变量,例如now,以及参数,例如name。下面是监视调用堆栈断点的窗格(详情请参见VS Code调试)。在局部变量部分,尝试展开不同的值。您还可以双击值(或使用Enter(Windows,Linux F2)来修改它们。然而,更改诸如now之类的变量可能会破坏程序。开发人员通常只在代码未生成正确值时才进行更改以修正值。

    Django教程:在VS Code调试期间的局部变量和参数

  8. 当程序暂停时,调试控制台面板(与终端面板中的“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'
    

    提示: 调试控制台 还会显示应用程序内部的异常,这些异常可能不会出现在终端中。例如,如果您在 运行和调试 视图的 调用堆栈 区域看到“暂停在异常”消息,请切换到 调试控制台 查看异常消息。

  9. 将该行复制到调试控制台底部的>提示符中,并尝试更改格式:

    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'
    
  10. 如果你愿意,可以逐步执行几行代码,然后选择继续(F5)让程序运行。浏览器窗口显示结果:

    Django教程:修改后的程序结果

  11. 更改代码中的行以使用不同的日期时间格式,例如 now.strftime("%a, %d %b, %y at %X"),然后保存文件。Django 服务器将自动重新加载,这意味着更改将应用而无需重新启动调试器。刷新浏览器上的页面以查看更新。

  12. 完成后关闭浏览器并停止调试器。要停止调试器,请使用停止工具栏按钮(红色方块)或运行 > 停止调试命令(⇧F5 (Windows, Linux Shift+F5))。

提示: 为了方便重复导航到特定的URL,如http://127.0.0.1:8000/hello/VSCode,可以在文件如views.py中的某个地方使用print语句输出该URL。该URL会出现在VS Code终端中,您可以使用Ctrl+点击在浏览器中打开它。

转到定义和查看定义命令

在使用Django或任何其他库时,您可能希望检查这些库中的代码。VS Code提供了两个方便的命令,可以直接导航到任何代码中类和其他对象的定义:

  • 转到定义 从您的代码跳转到定义对象的代码。例如,在 views.py 中,右键点击 home 函数中的 HttpResponse 并选择 转到定义(或使用 F12),这将导航到 Django 库中的类定义。

  • Peek Definition (⌥F12 (Windows Alt+F12, Linux Ctrl+Shift+F10), 也可以在右键菜单中找到), 是类似的,但直接在编辑器中显示类定义(在编辑器窗口中腾出空间以避免遮挡任何代码)。按 Escape 关闭 Peek 窗口或使用右上角的 x

    Django教程:内联显示Flask类的Peek Definition

使用模板渲染页面

在本教程中,您到目前为止创建的应用程序仅从Python代码生成纯文本网页。尽管可以直接在代码中生成HTML,但开发者避免这种做法,因为它会使应用程序容易受到跨站脚本(XSS)攻击。例如,在本教程的hello_there函数中,有人可能会想到用类似content = "

Hello there, " + clean_name + "!

"的代码格式化输出,其中content的结果直接提供给浏览器。这种开放方式允许攻击者在URL中放置恶意HTML,包括JavaScript代码,这些代码最终会出现在clean_name中,从而在浏览器中运行。

一个更好的做法是通过使用模板将HTML完全从代码中移除,这样你的代码只关注数据值而不关注渲染。

在Django中,模板是一个包含占位符的HTML文件,这些占位符用于在运行时由代码提供值。Django模板引擎在渲染页面时负责进行替换,并提供自动转义以防止XSS攻击(也就是说,如果你尝试在数据值中使用HTML,你只会看到HTML被渲染为纯文本)。因此,代码只关注数据值,而模板只关注标记。Django模板提供了灵活的选项,如模板继承,允许你定义一个具有通用标记的基础页面,然后在此基础上添加特定页面的内容。

在本节中,您首先使用模板创建一个单页。在后续部分中,您将配置应用程序以提供静态文件,然后为应用程序创建多个页面,每个页面都包含来自基础模板的导航栏。Django模板还支持控制流和迭代,正如您在本教程后面的模板调试部分中所见。

  1. web_project/settings.py文件中,找到INSTALLED_APPS列表并添加以下条目,这确保项目知道应用程序,以便它可以处理模板:

    'hello',
    
  2. hello文件夹内,创建一个名为templates的文件夹,然后再创建一个名为hello的子文件夹以匹配应用程序名称(这种双层文件夹结构是典型的Django惯例)。

  3. 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>
    
  4. views.py 的顶部,添加以下导入语句:

    from django.shortcuts import render
    
  5. 同样在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()
            }
        )
    

    你可以看到代码现在简单多了,只关注数据值,因为标记和格式都包含在模板中。

  6. 启动程序(在调试器内部或外部,使用 ⌃F5 (Windows, Linux Ctrl+F5)),导航到 /hello/name URL,并观察结果。

  7. 也可以尝试使用类似的名称导航到/hello/name URL,以查看Django的自动转义功能。"name"值在浏览器中显示为纯文本,而不是渲染为实际元素。

提供静态文件

静态文件是您的Web应用程序为某些请求(如CSS文件)按原样返回的内容。提供静态文件需要在settings.py中的INSTALLED_APPS列表包含django.contrib.staticfiles,默认情况下已包含。

在Django中提供静态文件是一种艺术,尤其是在部署到生产环境时。这里展示的是一种简单的方法,适用于Django开发服务器以及像Gunicorn这样的生产服务器。然而,关于静态文件的完整处理超出了本教程的范围,因此更多信息请参阅Django文档中的管理静态文件

切换到生产环境时,导航到settings.py,设置DEBUG=False,并将ALLOWED_HOSTS = ['*']更改为允许特定主机。在使用容器时,这可能会导致额外的工作。详情请参阅Issue 13

准备应用程序以处理静态文件

  1. 在项目的web_project/urls.py中,添加以下import语句:

    from django.contrib.staticfiles.urls import staticfiles_urlpatterns
    
  2. 在同一文件中,在末尾添加以下行,该行将标准静态文件URL包含到项目识别的列表中:

    urlpatterns += staticfiles_urlpatterns()
    

在模板中引用静态文件

  1. hello文件夹中,创建一个名为static的文件夹。

  2. static文件夹中,创建一个名为hello的子文件夹,与应用程序名称匹配。

    这个额外的子文件夹的原因是,当你将Django项目部署到生产服务器时,你会将所有静态文件收集到一个单独的文件夹中,然后由专用的静态文件服务器提供服务。static/hello子文件夹确保在收集应用程序的静态文件时,它们位于特定于应用程序的子文件夹中,并且不会与同一项目中其他应用程序的文件发生冲突。

  3. static/hello文件夹中,创建一个名为site.css的文件,内容如下。输入此代码后,还可以观察VS Code为CSS文件提供的语法高亮,包括颜色预览。

    .message {
        font-weight: 600;
        color: blue;
    }
    
  4. templates/hello/hello_there.html中,在元素后添加以下行。{% load static %}标签是一个自定义的Django模板标签集,它允许你使用{% static %}来引用像样式表这样的文件。

    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'hello/site.css' %}" />
    
  5. 同样在 templates/hello/hello_there.html 中,将 元素的内容替换为以下使用 message 样式而不是 标签的标记:

    <span class="message">Hello, there {{ name }}!</span> It's {{ date | date:'l, d F, Y' }} at {{ date | time:'H:i:s' }}.
    
  6. 运行应用程序,导航到 /hello/name URL,并观察消息是否以蓝色呈现。完成后停止应用程序。

使用 collectstatic 命令

对于生产部署,您通常使用python manage.py collectstatic命令从您的应用程序中收集所有静态文件到一个单独的文件夹中。然后,您可以使用专用的静态文件服务器来提供这些文件,这通常会带来更好的整体性能。以下步骤展示了如何进行这种收集,尽管在使用Django开发服务器运行时您不会使用这种收集。

  1. web_project/settings.py中,添加以下行,定义在使用collectstatic命令时收集静态文件的位置:

    STATIC_ROOT = BASE_DIR / 'static_collected'
    
  2. 在终端中,运行命令 python manage.py collectstatic 并观察 hello/site.css 被复制到与 manage.py 同级的顶级 static_collected 文件夹中。

  3. 在实践中,每当您更改静态文件并在部署到生产环境之前,请运行collectstatic

创建多个扩展基础模板的模板

因为大多数网络应用程序都有多个页面,而且这些页面通常共享许多共同的元素,开发者将这些共同的元素分离到一个基础页面模板中,然后其他页面模板再扩展这个基础页面模板。(这也被称为模板继承,意味着扩展的页面从基础页面继承元素。)

此外,由于您可能会创建许多扩展相同模板的页面,因此在VS Code中创建一个代码片段非常有用,您可以使用它快速初始化新的页面模板。代码片段可以帮助您避免繁琐且容易出错的复制粘贴操作。

以下部分将逐步介绍此过程的不同部分。

创建一个基础页面模板和样式

Django中的基础页面模板包含一组页面的所有共享部分,包括对CSS文件、脚本文件等的引用。基础模板还定义了一个或多个标签,扩展模板预计会覆盖这些标签的内容。块标签在基础模板和扩展模板中由{% block %}{% endblock %}界定。

以下步骤演示了如何创建一个基础模板。

  1. 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>&copy; 2018</p>
        </footer>
    </div>
    </body>
    </html>
    
  2. 将以下样式添加到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,所以创建一个代码片段来初始化一个新的模板文件并引用基础模板可以节省时间。代码片段提供了一个来自单一来源的一致代码片段,这避免了从现有代码中复制粘贴时可能出现的错误。

  1. 在 VS Code 中,选择 文件(Windows/Linux)或 代码(macOS)菜单,然后选择 首选项 > 用户片段

  2. 在出现的列表中,选择html。(如果您之前创建过代码片段,该选项可能会在列表的现有代码片段部分显示为“html.json”。)

  3. 在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"
    },
    
  4. 保存html.json文件(⌘S(Windows, Linux Ctrl+S)。

  5. 现在,每当你开始输入代码片段的前缀,例如djext,VS Code 会将该片段作为自动完成选项提供,如下一节所示。你也可以使用插入片段命令从菜单中选择一个片段。

有关代码片段的更多信息,请参阅创建片段

使用代码片段添加页面

有了这段代码片段,你可以快速为首页、关于和联系页面创建模板。

  1. templates/hello文件夹中,创建一个名为home.html的新文件,然后开始输入djext以查看片段作为补全出现:

    Django教程:djextlayout代码片段的自动补全

    当你选择完成时,代码片段会显示出来,光标位于代码片段的插入点:

    Django教程:插入djextlayout代码片段

  2. 在“title”块的插入点处,写入Home,在“content”块中写入

    Visual Studio Code Django教程的主页。

    ,然后保存文件。这些行是扩展页面模板中唯一独特的部分:

  3. templates/hello文件夹中,创建about.html,使用代码片段插入样板标记,分别在“title”和“content”块中插入About us

    关于Visual Studio Code Django教程的页面。

    ,然后保存文件。

  4. 重复上一步,使用Contact us

    Visual Studio Code Django教程的联系页面。

    创建templates/hello/contact.html

  5. 在应用程序的urls.py中,为/about和/contact页面添加路由。请注意,path函数的name参数定义了你在模板中的{% url %}标签中引用页面的名称。

    path("about/", views.about, name="about"),
    path("contact/", views.contact, name="contact"),
    
  6. 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,运行应用程序,并在浏览器中打开主页以查看结果。在页面之间导航以验证页面模板是否正确扩展了基础模板。

Django教程:应用从基础模板渲染一个共同的导航栏

处理数据、数据模型和迁移

许多网络应用程序使用存储在数据库中的信息,而Django使得使用模型来表示该数据库中的对象变得容易。在Django中,模型是一个Python类,继承自django.db.models.Model,它代表一个特定的数据库对象,通常是一个表。您将这些类放在应用程序的models.py文件中。

使用Django,您几乎完全通过您在代码中定义的模型与数据库进行交互。随着模型的不断演变,Django的“迁移”会自动处理底层数据库的所有细节。一般的工作流程如下:

  1. 在您的models.py文件中更改模型。
  2. 运行 python manage.py makemigrations 以在 migrations 文件夹中生成脚本,这些脚本将数据库从当前状态迁移到新状态。
  3. 运行 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 万次访问的低到中等流量的网站,但不建议用于更高流量的场景。它还仅限于单台计算机,因此不能用于任何多服务器场景,如负载均衡和地理复制。

出于这些原因,考虑使用生产级别的数据存储,例如 PostgreSQLMySQLSQL Server。有关 Django 对其他数据库的支持信息,请参阅 数据库设置。您还可以使用 Azure SDK for Python 来处理 Azure 存储服务,如表格和 blob。

定义模型

Django模型再次是从django.db.model.Models派生的Python类,您将其放置在应用程序的models.py文件中。在数据库中,每个模型都会自动获得一个名为id的唯一ID字段。所有其他字段都使用django.db.models中的类型定义为类的属性,例如CharField(有限文本)、TextField(无限文本)、EmailFieldURLFieldIntegerFieldDecimalFieldBooleanFieldDateTimeFieldForeignKeyManyToMany等。(有关详细信息,请参阅Django文档中的模型字段参考。)

每个字段都有一些属性,比如max_lengthblank=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生成的脚本。你也可以查看数据库本身,看看模式是否已更新。

如果在运行命令时看到错误,请确保您没有使用之前步骤中遗留的调试终端,因为它们可能没有激活虚拟环境。

通过模型使用数据库

在您的模型就位并且数据库迁移后,您可以仅使用您的模型来存储和检索数据。在本节中,您将向应用程序添加一个表单页面,通过该页面您可以记录消息。然后,您将修改主页以显示这些消息。因为您在这里修改了许多代码文件,所以请注意细节。

  1. 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
    
  2. 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文档中的跨站请求伪造保护

  3. 在应用程序的 static/hello/site.css 文件中,添加一条规则以使输入表单更宽:

    input[name=message] {
        width: 80%;
    }
    
  4. 在应用程序的urls.py文件中,为新页面添加一个路由:

    path("log/", views.log_message, name="log"),
    
  5. 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})
    
  6. 在您准备好尝试一切之前,还有一步!在templates/hello/layout.html中,为消息记录页面在“navbar” div中添加一个链接:

    <!-- Insert below the link to Home -->
    <a href="{% url 'log' %}" class="navbar-item">Log Message</a>
    
  7. 运行应用程序并打开浏览器访问主页。在导航栏中选择Log Message链接,这将显示消息记录页面:

    Django教程:添加到应用程序的消息记录页面

  8. 输入一条消息,选择日志,你应该会被带回到主页。主页目前还没有显示任何已记录的消息(你稍后会解决这个问题)。随意记录更多的消息。如果你愿意,可以使用像SQLite浏览器这样的工具查看数据库中是否已创建记录。以只读方式打开数据库,或者在使用应用程序之前记得关闭数据库,否则应用程序会因为数据库被锁定而失败。

  9. 完成后停止应用程序。

  10. 现在修改主页以显示已记录的消息。首先,将应用程序的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 %}
    
  11. static/hello/site.css中,添加一条规则来稍微格式化表格:

    .message_list th,td {
        text-align: left;
        padding-right: 15px;
    }
    
  12. views.py中,导入Django的通用ListView类,我们将使用它来实现主页:

    from django.views.generic import ListView
    
  13. 同样在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
    
  14. 在应用程序的 urls.py 中,导入数据模型:

    from hello.models import LogMessage
    
  15. 同样在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",
    )
    
  16. urls.py中,修改主页路径以使用home_list_view变量:

        # Replace the existing path for ""
        path("", home_list_view, name="home"),
    
  17. 启动应用程序并打开浏览器到主页,现在应该显示消息:

    Django教程:显示来自数据库消息的应用主页

  18. 完成后停止应用程序。

使用调试器与页面模板

如前一节所示,页面模板可以包含过程性指令,如{% for message in message_list %}{% if message_list %},而不仅仅是像{% url %}{% block %}这样的被动声明性元素。因此,与任何其他过程性代码一样,模板内部也可能出现编程错误。

幸运的是,当你在调试配置中有"django": true时(正如你已经做的那样),VS Code的Python扩展提供了模板调试功能。以下步骤展示了这一功能:

  1. templates/hello/home.html中,在{% if message_list %}{% for message in message_list %}这两行设置断点,如下图所示中的黄色箭头所示:

    Django教程:在Django页面模板中设置的断点

  2. 在调试器中运行应用程序并打开浏览器到主页。(如果您已经在运行调试器,设置断点后不需要重新启动应用程序;只需刷新页面。)观察VS Code在模板中的{% if %}语句处进入调试器,并在变量面板中显示所有上下文变量:

    Django教程:调试器在页面模板的断点处停止

  3. 使用“单步跳过”(F10)命令来逐步执行模板代码。观察调试器跳过所有声明性语句并在任何过程代码处暂停。例如,逐步执行{% for message in message_list %}循环可以让您检查message中的每个值,并让您逐步执行像{{ message.log_date | date:'d M Y' }}这样的行。

  4. 你也可以在调试控制台面板中使用变量。(不过,像date这样的Django过滤器目前在控制台中不可用。)

  5. 当你准备好时,选择继续(F5)以完成应用程序的运行并在浏览器中查看渲染的页面。完成后停止调试器。

可选活动

以下部分描述了在使用Python和Visual Studio Code时,您可能会发现有用的额外步骤。

为环境创建一个requirements.txt文件

当你通过源代码控制或其他方式分享你的应用代码时,复制虚拟环境中的所有文件是没有意义的,因为接收者总是可以自己重新创建那个环境。

因此,开发者通常会将虚拟环境文件夹从源代码控制中省略,而是使用requirements.txt文件来描述应用程序的依赖关系。

虽然你可以手动创建文件,但你也可以使用pip freeze命令根据激活环境中安装的精确库生成文件:

  1. 使用Python: 选择解释器命令选择您选择的环境后,运行终端: 创建新终端命令(⌃⇧` (Windows, Linux Ctrl+Shift+`)))以打开一个激活了该环境的终端。

  2. 在终端中,运行 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 中。

执行以下步骤以启用管理界面:

  1. 在应用程序中创建一个超级用户账户,通过在VS Code中为你的虚拟环境打开一个终端,然后运行命令python manage.py createsuperuser --username= --email=,当然,用你的个人信息替换。当你运行这个命令时,Django会提示你输入并确认你的密码。

    请务必记住您的用户名和密码组合。这些是您用于与应用程序进行身份验证的凭据。

  2. 在项目级别的urls.py(本教程中为web_project/urls.py)中添加以下URL路由,以指向内置的管理界面:

    # This path is included by default when creating the app
     path("admin/", admin.site.urls),
    
  3. 运行服务器,然后在浏览器中打开应用程序的/admin页面(例如在使用开发服务器时,打开http://127.0.0.1:8000/admin)。

  4. 出现一个登录页面,由django.contrib.auth提供。输入您的超级用户凭据。

    Django教程:默认的Django登录提示

  5. 一旦你通过认证,你将看到默认的管理页面,通过该页面你可以管理用户和组:

    Django教程:默认的Django管理界面

你可以根据需要自定义管理界面。例如,你可以提供编辑和删除数据库中条目的功能。有关进行自定义的更多信息,请参阅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应用服务。Azure还提供了一个标准容器,Linux上的应用服务,您可以从VS Code内部将Web应用程序部署到该容器。

您可能还想查看VS Code文档中与Python相关的以下文章: