【Web应用开发笔记】Django笔记3:模版的用法-实现一个简单的网页

1. Django 编写视图的方式

1.1 三种方式

  • 在 Django 中有三种不同的方式来编写视图:
    • 基于函数的
    • 基于类
    • 通用的基于类的
  • 通用的基于类的视图是最难理解的。整整一个网站《Classy Class-Based Views》专门用于帮助开发者解析它们。

1.2 三种方式如何选择

  • 视图的三种不同编写方式的推荐方法:
    • 首先会选择通用的基于类的视图。有很多问题可以通过现成的 GCVB(如 TemplateView、ListView 或 DetailView)解决。
    • 当通用基于类的视图不足以满足需求时,可以对其进行修改以适应你的需求。
    • 如果这仍然不够,那么就回退到基于函数基于类的视图。

2. 创建项目

2.0 前置操作

  • 如上一篇博客《【Web应用开发笔记】Django笔记2:一个 Hello World 网页》中介绍了创建项目相关的操作,这里不再赘述。总结如下:

    • 创建 python 环境(包括导入包)
    • 创建 Django 项目
    • 创建 pages APP(包括修改相关代码)
  • 后续的操作均基于上一篇博客创建的项目

  • 这里我补充一点:

    • 我将之前名为 py3p11_Django 的 python 环境删除了。
    • 与 conda 方式安装 python 环境不同的是,通过 apt install 加 python3.11 -m venv 方式创建的环境只需要直接 rm -rf 环境文件夹即可删除环境。
    • 我按照书里说的重新创建了名为 .venv 的环境,主要是为了让这个目录在项目里看起来更规范。
  • 在创建以及修改项目的过程中,记住下面的图有助于你理清思路

2.1 第一个 Django 模版:Home 页面

2.1.1 创建模版页面

  • 在项目中创建一个 templates 文件夹
bash 复制代码
mkdir templates

现在的项目目录结构是这样

text 复制代码
├── .venv/
├── django_project/
├── pages/
├── templates/ # new <===
├── db.sqlite3
└── manage.py
  • 在 django_project/settings.py 中修改 TEMPLATES 变量如下
python 复制代码
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            BASE_DIR / "templates" # new <===
        ],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]
  • 在 templates/ 文件夹下创建 home.html
html 复制代码
<!-- templates/home.html -->
<h1>Homepage</h1>

2.1.2 修改 pages APP 相关代码

  • pages/views.py
python 复制代码
from django.views.generic import TemplateView

class HomePageView(TemplateView):
    template_name = "home.html"
  • pages/urls.py
python 复制代码
from django.urls import path
from .views import HomePageView

urlpatterns = [
    path("", HomePageView.as_view(), name="home"),
]
  • django_project/urls.py
python 复制代码
from django.contrib import admin
from django.urls import path, include # new

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("pages.urls")), # new
]

2.1.3 重启服务

bash 复制代码
python manage.py runserver

2.2 第二个 Django 模版:About 页面

2.2.1 新页面需要修改哪些东西

由于我们前面已经创建过一个页面,并且修改了一些代码,因此在新增一个独立页面的时候,就不需要修改那么多地方了。

我们需要修改的是

  • templates/ 下新增 About页面
  • 修改 pages APP 下的 views 和 urls

2.2.2 新增、修改的具体内容

  • 新增 templates/about.html
python 复制代码
<!-- templates/about.html -->
<h1>About page</h1>
  • 修改 pages/views.py
python 复制代码
from django.views.generic import TemplateView

class HomePageView(TemplateView):
    template_name = "home.html"

class AboutPageView(TemplateView): # new <===
    template_name = "about.html"
  • 修改 pages/urls.py
python 复制代码
from django.urls import path
from .views import HomePageView, AboutPageView # new <===

urlpatterns = [
    path("", HomePageView.as_view(), name="home"),
    path("about/", AboutPageView.as_view(), name="about"), # new <===
]

2.2.3 重启服务

注意这里的网址需要加 about/ 结尾,因为我们在 pages/urls.py 里面给 About页面 配置的路径就是这个

2.3 扩展模版

在上面的例子里,有一些问题:

  • 这两个页面还没有联系,比如我在 home 页面是无法跳转到 about 页面的。
  • 如果这两个页面需要相同的某些内容,比如一个公共的头部导航之类的,可以有什么方式来复用吗?

本小节就来解决以上问题。

2.3.1 页面修改

  • 新建 templates/base.html
html 复制代码
<!-- templates/base.html -->
<header>
    <a href="{% url 'home' %}">Home</a> |
    <a href="{% url 'about' %}">About</a>
</header>

{% block content %} {% endblock content %}
  • 修改 templates/home.html
html 复制代码
<!-- templates/home.html -->
{% extends "base.html" %}

{% block content %}
<h1>Homepage</h1>
{% endblock content %}
  • 修改 templates/about.html
html 复制代码
<!-- templates/about.html -->
{% extends "base.html" %}

{% block content %}
<h1>About page</h1>
{% endblock content %}

2.3.2 重启服务

可以看到:

  • 这个页面上有了简单的导航,通过点击 Home | About 就可以跳转到对应的页面上。
  • Home 和 About 页面上都有第一行这个导航。

2.3.3 ★ 解析 ★

作为新手,这三个 html 虽然内容不多,但是确实需要花费一定精力来理解。

前面的三个 html 实际是 html 语法 和 Django 模版语法的混合写法,是 Django 为了模版专门适配的写法。

下面简单介绍。

2.3.3.1 html 语法
  • 写法
html 复制代码
<!-- 注释 -->
<标签名 属性="值">内容</标签名>
  • 举例
html 复制代码
<!-- 示例 -->
<a href="https://example.com">点击这里</a>
  • 标签可嵌套
2.3.3.2 Django 模版在 html 中的语法
语法 类型 含义
{% extends "base.html" %} 模板标签 继承 父模板,必须放在子模板最顶部
{% block content %} 模板标签 定义一个名为 "content" 的内容块(开始)
{% endblock content %} 模板标签 结束 "content" 块(content 可省略,但建议写上)
{% url 'home' %} 模板标签 根据 URL 名称反向解析出实际 URL ,这和 urls.py 代码中指定的 name="home"是对应的
{``{ variable }} 模板变量 输出变量值(双花括号,你例子中没用到)
  • 关于 {% block content %} {% endblock content %}
    • 父模板(base.html)用 {% block content %} 挖一个"坑"
    • 子模板(home.html/about.html)用同样的 {% block content %} 来"填坑"
    • 块名(content)可以自定义,但父子必须匹配
  • 由此再回顾三个 html 的内容,可以看出它们之间的关系:
text 复制代码
base.html (父模板/基础框架)
    ├── home.html (子模板)  ← 填充 content 块为 "Homepage"
    └── about.html (子模板) ← 填充 content 块为 "About page"
2.3.3.4 总结
概念 属于 作用
<a><header><h1> HTML 定义网页结构和语义
{% extends %}{% block %}{% url %} Django 模板语言 实现模板继承和动态内容
name='home' Django URL 配置 py代码 为 URL 路径提供可引用的标识符

3. 测试

3.1 简介

  • 测试的目的
    • 保证功能
    • 保障性能
    • 保障稳定性
  • 测试的类型
    • 单元测试:模块
    • 集成测试:整体
  • 注意点
    • 例如新增了功能,此时不仅需要验证新功能是否正常(单元测试),也要保证新功能不会影响老功能(集成测试)

3.2 python & Django 提供的标准测试工具

  • python
    • 内置的测试框架:unittest
      • 使用 TestCase 实例
      • 长的断言方法
  • Django
    • 用于发起模拟 Web 浏览器请求的测试客户端
    • Django 特有的额外断言
    • 四个测试用例类:
      • SimpleTestCase:不需要数据库时使用
      • TestCase:想测试数据库时使用
      • TransactionTestCase:对直接测试数据库事务很有帮助
      • LiveServerTestCase:启动一个实时服务器线程,用于与基于浏览器的工具(如 Selenium)进行测试
测试类 用途 数据库支持
SimpleTestCase 测试不依赖数据库的基本功能(URL、视图、模板) ❌ 不创建测试数据库
TestCase 测试依赖数据库的功能(模型、表单、数据库操作) ✅ 自动创建并隔离测试数据库
LiveServerTestCase 启动真实服务器进行集成测试(如 Selenium 测试) ✅ 支持
TransactionTestCase 测试数据库事务行为 ✅ 每个测试后回滚事务
  • 基本用法

    • 继承4个基础类中的某一个
    • 测试函数(类的成员函数)。Django 基于 Python 的 unittest 框架,只要求遵循一个约定:
      • 函数名必须以 test_ 开头
    • 运行测试
      • python manage.py test
  • 常用工具

    • self.client:内置的 HTTP 客户端,模拟 GET/POST 请求
    • reverse():根据 URL 名称反向解析路径(与模板中的 {% url %} 对应)
    • 断言方法:assertEqual()、assertContains()、assertTemplateUsed() 等
  • 注:unittest 和 django.test 中方法的命名是使用 camelCase 而不是更符合 Python 风格的 snake_case。原因是 unittest 基于 Java 的 jUnit 测试框架,而 jUnit 使用的是 camelCase,因此当 Python 引入 unittest 时,也采用了 camelCase 命名。

3.3 测试本项目

测试内容 成功标志
url是否能够访问 是否都返回 HTTP 状态码 200,这是 HTTP 请求成功的标准响应
页面展示是否正常 可以测试的内容包括:页面名称是否正确、模版html是否正常使用、页面返回内容是否包含目标内容
  • 测试内容:
    • home 和 about 页面的url是否能够访问 - 是否都返回 HTTP 状态码 200,这是 HTTP 请求成功的标准响应
  • 关键:是否都返回 HTTP 状态码 200,这是 HTTP 请求成功的标准响应
  • 代码
python 复制代码
# pages/tests.py
from django.test import SimpleTestCase
from django.urls import reverse

class HomepageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/")
        self.assertEqual(response.status_code, 200)

    def test_url_available_by_name(self):
        response = self.client.get(reverse("home"))
        self.assertEqual(response.status_code, 200)

    def test_template_name_correct(self):
        response = self.client.get(reverse("home"))
        self.assertTemplateUsed(response, "home.html")

    def test_template_content(self):
        response = self.client.get(reverse("home"))
        self.assertContains(response, "<h1>Homepage</h1>")

class AboutpageTests(SimpleTestCase):
    def test_url_exists_at_correct_location(self):
        response = self.client.get("/about/")
        self.assertEqual(response.status_code, 200)

    def test_url_available_by_name(self):
        response = self.client.get(reverse("about"))
        self.assertEqual(response.status_code, 200)

    def test_template_name_correct(self):
        response = self.client.get(reverse("about"))
        self.assertTemplateUsed(response, "about.html")
    
    def test_template_content(self): 
        response = self.client.get(reverse("about"))
        self.assertContains(response, "<h1>About page</h1>")
  • 解释(以 HomepageTests 中的四个用例为例, about 页面同理不赘述)
测试方法 访问方式 测试重点
test_url_exists_at_correct_location "/" 硬编码路径 验证根路径是否存在且可访问(HTTP 200)
test_url_available_by_name reverse("home") 反向解析 验证 URL 名称 home 能正确解析到对应路径
test_template_name_correct reverse("home") 反向解析 验证视图渲染的是正确的模板文件 home.html
test_template_content reverse("home") 反向解析 验证返回的页面内容中包含预期的 HTML 片段 <h1>Homepage</h1>
text 复制代码
test_url_exists_at_correct_location  →  路径通不通?(最基础)
        ↓
test_url_available_by_name           →  名称解析对不对?
        ↓
test_template_name_correct           →  用了哪个模板?
        ↓
test_template_content                →  内容对不对?(最严格)
  • 运行
bash 复制代码
python manage.py test

这表示 home 页面和 about 页面的8个用例均测试通过

4. 小结:创建一个不涉及数据库的 Web 应用

本文重点用 ☆ 标记

  • 环境配置:python、Django
  • 创建项目
    • 创建初始数据库 并 注册到 settings 中 (仅为了消除告警)
    • 创建 APP 并 注册到 settings 中
      • 创建模版 html ☆
      • 创建 view(指向 html) ☆
      • 创建 URL 配置 (使用 view) ☆
  • 测试 ☆
    • 编写测试用例 ☆
    • 测试 ☆
  • 启动服务
    • 人工检视
相关推荐
Autumn72991 小时前
【系统重装】PYTHON 入门——速通版
开发语言·python·conda·cuda
24白菜头1 小时前
2026-2-23:LeetCode每日一题(动态规划专项)
笔记·学习·算法·leetcode·动态规划
FL16238631291 小时前
基于yolov11+django+deepseek的血液细胞红白细胞血小板检测系统带登录界面python源码+onnx模型+精美web界面
python·yolo·django
土拨鼠烧电路2 小时前
笔记09:产品与研发:爆款、成分与上市生死时速
笔记
啊阿狸不会拉杆2 小时前
《计算机视觉:模型、学习和推理》第 9 章-分类模型
人工智能·python·学习·算法·机器学习·计算机视觉·分类
Dxy12393102162 小时前
DataFrame缺失值处理:完整指南与实战技巧
python·pandas·dataframe
geovindu2 小时前
python: Visitor Pattern
python·设计模式·访问者模式
_Twink1e2 小时前
[算法竞赛]四、树
数据结构·笔记·算法