第 4 章:公司网站
在本章中,我们将构建第三个项目——一个公司网站,同时进一步学习模板知识,引入基于类的视图(CBV),并编写更高级的测试。这是我们在接触数据库和 Django 模型之前的最后一个项目,因此这是巩固之前所学知识、探索 Django 另外三个组成部分——视图、URL 和模板——更多功能的好机会。
初始设置
我们的初始设置现在应该开始变得熟悉了,包含以下步骤:
- 为代码创建一个名为
company的新目录并进入该目录 - 创建一个名为
.venv的新虚拟环境并激活它 - 安装 Django 和 Black
- 创建一个名为
django_project的新 Django 项目 - 创建一个名为
pages的新应用
在命令行中,确保你不在现有的虚拟环境中工作。如果命令行提示符(Windows 上是 >,macOS 上是 %)之前有文本,说明你在!请务必输入 deactivate 退出。
在新的命令行终端中,导航到桌面上的 code 文件夹,创建一个名为 company 的新文件夹,进入该目录,并激活一个名为 .venv 的新 Python 虚拟环境。
# Windows
$ cd onedrive\desktop\code
$ mkdir company
$ cd company
$ python -m venv .venv
$ .venv\Scripts\Activate.ps1
(.venv) $
# macOS
$ cd ~/desktop/code
$ mkdir company
$ cd company
$ python3 -m venv .venv
$ source .venv/bin/activate
(.venv) $接下来,安装 Django 和 Black,创建一个名为 django_project 的新项目,并创建一个名为 pages 的新应用。我们一直将所有应用称为”pages”,因为它们一直用于相对静态的页面。在未来的项目中,我们将从数据库中填充页面,应用名称将反映这种新的动态。
(.venv) $ python -m pip install django~=5.0.0
(.venv) $ python -m pip install black
(.venv) $ django-admin startproject django_project .
(.venv) $ python manage.py startapp pages请记住,即使我们添加了新应用,Django 也不会自动识别它,直到在 django_project/settings.py 的 INSTALLED_APPS 设置中明确添加。现在打开文本编辑器,将其添加到底部:
# django_project/settings.py
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"pages", # 新增
]使用 migrate 初始化数据库,然后用 runserver 启动本地 Web 服务器。
(.venv) $ python manage.py migrate
(.venv) $ python manage.py runserver然后导航到 http://127.0.0.1:8000/ 查看 Django 欢迎页面。
项目级别的模板
之前我们已经看到,Django 期望模板文件位于应用内的 templates 目录中,并且最佳实践是通过再次添加目录名来进一步命名空间化。换句话说,pages 应用的模板文件应该位于 pages/templates/pages/ 目录中。
然而,许多 Django 开发者青睐另一种方法:创建一个单一的项目级别 templates 目录,并将所有模板放置在其中。这样更容易在同一个位置查找和更新所有模板。通过调整 django_project/settings.py 文件,我们可以告诉 Django 在这个目录中查找模板。
首先,按 Control+c 停止正在运行的服务器。然后,创建一个名为 templates 的目录。
(.venv) $ mkdir templates接下来,我们需要更新 django_project/settings.py,告诉 Django 新的 templates 目录在哪里。这需要在 TEMPLATES 下对 "DIRS" 配置做一行修改。
# django_project/settings.py
TEMPLATES = [
{
...
"DIRS": [BASE_DIR / "templates"], # 新增
...
},
]我们将在本书的其余部分使用这种组织模板的方式。在 templates 目录中创建一个名为 home.html 的新文件。你可以在文本编辑器中完成:在 Visual Studio Code 中,转到屏幕左上角,点击”File”,然后点击”New File”。确保在正确的位置命名并保存文件。
目前,home.html 文件将包含一个简单的标题。
<!-- templates/home.html -->
<h1>Company Homepage</h1>模板完成了!下一步是配置 URL 和视图文件。
基于函数的视图和 URL
先写视图还是先写 URL,完全由开发者决定。最终,我们需要两者来显示网页,因此随着时间的推移,决定执行顺序变成了个人偏好。这里,我们从 pages 应用中的视图开始。
# pages/views.py
from django.shortcuts import render
def home_page_view(request): # 新增
return render(request, "home.html")这段代码看起来应该很熟悉,和上一章一样。我们使用了顶部导入的 render() 快捷函数。然后创建了视图 home_page_view,并将其第一个参数(HttpRequest 对象)命名为 request。我们返回 request 对象并指定了正确的模板文件 home.html。
接下来是 URL 配置,包括作为网站入口点的项目级 urls.py 文件和应用级 urls.py 文件(包含首页的具体路由和视图)。
django_project/urls.py 文件是所有 URL 请求进入我们项目的初始入口点。我们必须在顶部导入 include 函数,然后使用它来包含 pages 应用中的 URL 路由,这些路由将设置为空字符串 ""。
# django_project/urls.py
from django.contrib import admin
from django.urls import path, include # 新增
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("pages.urls")), # 新增
]应用级别的 pages/urls.py 文件导入视图 home_page_view,并将其设置为空字符串 "" 的 URL 路径。
# pages/urls.py
from django.urls import path
from .views import home_page_view
urlpatterns = [
path("", home_page_view),
]使用 runserver 命令启动开发 Web 服务器。
(.venv) $ python manage.py runserver如果你导航到 http://127.0.0.1:8000/,首页现在可见。
!基于函数的视图:公司首页
很简单,对吧?到目前为止,唯一引入的新概念是项目级别的模板目录。
模板上下文、标签和过滤器
让我们为首页视图添加一个模板上下文,然后试用一些 Django 的内置标签和过滤器。标签执行更复杂的操作,如循环、条件判断和模板继承。而过滤器则用于执行更简单的转换,修改变量的显示方式,例如格式化日期、截断文本或将字符串转换为大写。标签和过滤器太多了,不可能全部记住;你只需要知道,对于几乎任何内容显示需求,都有大量原生解决方案可用。
模板上下文具有键值对的字典结构。为了演示,我们可以添加两个:一个包含三个小部件的 inventory_list 和一个故意混合大小写字母的问候文字字符串 greeting。
# pages/views.py
from django.shortcuts import render
def home_page_view(request):
context = { # 新增
"inventory_list": ["Widget 1", "Widget 2", "Widget 3"],
"greeting": "THAnk you FOR visitING.",
}
return render(request, "home.html", context)用以下代码更新 home.html 模板文件。[now](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#now) 标签使用 [DATE_FORMAT](https://docs.djangoproject.com/en/5.0/ref/settings/#std-setting-DATE_FORMAT)(几种显示选项之一)显示当前日期和/或时间。接下来,使用 [length](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#length) 过滤器显示 inventory_list 中的项目数量,该过滤器既适用于字符串也适用于列表。
然后,在 [for](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#for) 标签中遍历每个项目。通用语法是 {% for item in item_list %},其中 item 是代表循环中当前项的变量名,item_list 是我们要循环的序列。同样关键的是,必须包含 {% endfor %} 标签来结束任何 for 循环。这里,序列名为 inventory_list。我们可以任意命名变量,但像 item 这样的描述性名称是常见选择,能使代码更容易理解。最后,我们使用 [title](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#title) 过滤器将字符串转换为标题大小写——每个单词以大写字母开头,后面跟小写字母。
<!-- templates/home.html -->
<h1>Company Homepage</h1>
<p>The current date and time is: {% now "DATETIME_FORMAT" %}</p>
<p>There are {{ inventory_list|length }} items of inventory.
<ul>
{% for item in inventory_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<p>{{ greeting|title }}</p>
{% comment %}Add more content here!{% endcomment %}本地 Web 服务器应该仍然在后台使用 runserver 命令运行,所以你只需刷新网页即可看到更改。
!带上下文的公司首页
这里的目的是不要让你被许多需要记忆的新 Django 功能所淹没。需要记住的标签和过滤器太多了。相反,要强调的是,对于你想到的几乎任何 Web 开发任务,Django 很可能都有一个内置的解决方案,这就是为什么官方文档不可或缺,也是专业 Django 开发者日常开发的一部分。
基于类的视图和通用基于类的视图
Django 社区中最接近宗教式辩论的问题是关于基于函数的视图(我们一直在使用的)和基于类的视图。早期版本的 Django 只提供了基于函数的视图,可以说它们比基于类的视图更容易理解,因为它们模拟了 HTTP 请求/响应周期。本书一开始只使用基于函数的视图正是出于这个原因。
基于函数的视图确实有缺点。它们缺乏简便的继承方式,这意味着开发者必须在每个视图中重复相同的代码片段。这违反了 Django 通用的 DRY(Don’t Repeat Yourself,不要重复自己)原则。但即使不重复相同的代码,基于函数的视图在实际项目中通常也会变得冗长,因此难以理解。看到包含十行、二十行甚至更多逻辑的视图是很常见的,这变得难以梳理。
Django 早期开发中引入了通用的基于函数的视图,以抽象常见模式并避免代码重复。例子包括:
- 编写显示单个模板的视图(就像我们刚才做的)
- 编写列出数据库模型中所有对象的视图
- 编写仅显示模型中单个详细项目的视图
- 编写创建、更新或删除对象的视图
通用的基于函数的视图的问题在于,没有简便的方法来扩展或自定义它们。随着项目规模的增长,这变得越来越成问题。
Django 添加了基于类的视图和通用基于类的视图来帮助实现代码可重用性,同时保留了基于函数的视图。类是 Python 中面向对象编程(OOP)和继承的基础部分,因此一个类可以从另一个类继承属性和方法。这意味着我们不需要在一个地方包含视图的所有逻辑,而是可以抽象出常见模式。
如果你需要 Python 中类的介绍或复习,我建议查看官方 Python 文档,其中有一个关于类及其用法的优秀教程。
一旦你使用通用基于类的视图一段时间,它们就会成为编写代码的优雅而高效的方式。你通常只需修改一个方法就能实现自定义行为,而不必从头重写所有内容,这使得理解他人的代码更加容易。然而,这是以复杂性为代价的,并且需要一种信念上的飞跃,因为需要很长时间才能理解它们在底层是如何工作的。有一个名为 Classy Class-Based Views 的整个网站致力于帮助 Django 开发者解读通用基于类的视图。
Django 代码库本身也已转变为主要使用基于类的视图和通用基于类的视图。通用的基于函数的视图在 Django 1.3 中被弃用,并在版本 1.5 中被完全移除。
这些年来 Django 的这些变化导致现在有三种不同的方式在 Django 中编写视图:基于函数的视图、基于类的视图和通用基于类的视图。这对初学者来说无疑是令人困惑的。
本书的早期版本完全专注于通用基于类的视图,但这个版本两者都包含。一个 Django 开发者需要理解每种方法的工作原理,即使随着时间的推移他们无疑会形成个人偏好。
TemplateView)
让我们为公司网站创建第二个网页,这次使用 [TemplateView](https://docs.djangoproject.com/en/5.0/ref/class-based-views/base/#django.views.generic.base.TemplateView))——一个通用的基于类的视图。这将是一个关于页面,同时利用模板上下文和 Django 模板语言。
在 views.py 文件的顶部,从 django.views.generic 模块中导入 [TemplateView](https://docs.djangoproject.com/en/5.0/ref/class-based-views/base/#django.views.generic.base.TemplateView)。然后创建一个类 AboutPageView,它继承 TemplateView 并指定一个模板 about.html。在 Python 中,类的命名惯例是使用”驼峰命名法(CamelCase)“,即每个单词的首字母大写,单词之间没有下划线。
# pages/views.py
from django.shortcuts import render
from django.views.generic import TemplateView # 新增
def home_page_view(request):
context = {
"inventory_list": ["Widget 1", "Widget 2", "Widget 3"],
"greeting": "THAnk you FOR visitING.",
}
return render(request, "home.html", context)
class AboutPageView(TemplateView): # 新增
template_name = "about.html"接下来,更新 pages/urls.py 文件以显示新视图。我们导入 AboutPageView 并将路由设置为 about/,同时指定 AboutPageView 作为视图。
# pages/urls.py
from django.urls import path
from .views import home_page_view, AboutPageView # 新增
urlpatterns = [
path("about/", AboutPageView.as_view()), # 新增
path("", home_page_view),
]注意添加了 as_view() 方法,它返回一个可调用的视图。配置基于类的视图与基于函数的视图的 URL 之间的唯一本质区别就是必须添加这个方法。
最后一步是创建模板文件 about.html。在你的文本编辑器中,在现有的 templates 目录中添加这个新文件,代码如下:
<!-- templates/about.html -->
<h1>Company About Page</h1>确保本地服务器正在运行,然后在浏览器中导航到 127.0.0.1:8000/about/。
!公司关于页面
很简单,对吧?
get_context_data()
Django 中最强大、最有用、最常用的方法之一是 get_context_data()。这是在通用基于类的视图中更新模板上下文的推荐方法。现在让我们使用它在关于页面中添加上下文数据。
# pages/views.py
...
class AboutPageView(TemplateView):
template_name = "about.html"
def get_context_data(self, **kwargs): # 新增
context = super().get_context_data(**kwargs)
context["contact_address"] = "123 Main Street"
context["phone_number"] = "555-555-5555"
return context
...首先,我们重写了现有的 get_context_data() 方法。第一个参数是 self,第二个是 **kwargs,允许我们传入关键字参数。这就是我们如何向上下文中添加键/值对的方法。
下一步是设置一个名为 context 的变量,其中包含上下文的现有值。怎么做呢?在 get_context_data 上调用 super() 并包含任何关键字参数。然后我们添加两个键 contact_address 和 phone_number 及其对应的值。最后一步始终是显式返回更新后的上下文。
要在模板中渲染上下文变量,我们使用双大括号 { }。
<!-- templates/about.html -->
<h1>Company About Page</h1>
<p>The company address is {{ contact_address }} and the phone number is
{{ phone_number }}.</p>刷新浏览器中的关于页面以查看显示的信息。
!带上下文的公司关于页面
目前,使用通用基于类的视图可能看起来没必要,但它们的真正威力将在下一章我们开始使用数据库时显现出来。
模板继承
这一章全是关于模板和视图的。我们已经涵盖了很多信息:模板上下文、模板标签和过滤器,以及基于类的视图。然而,模板还有一个强大的功能——它们可以被扩展。
如果你思考大多数网站,相同的内容会出现在每个页面上(页眉、页脚等)。作为开发者,如果我们能有一个统一的地方放置页眉代码,而所有其他模板都能继承它,那该多好?没错,我们可以!
在 templates 目录中,创建一个 base.html 文件,其中包含一个指向首页和关于页面的链接的页眉。这是父模板,所有其他子模板都将继承自它。要定义哪些区域可以被覆盖,我们将使用 [block](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#block) 标签,语法为 {% block content %} 和 {% endblock %}。block 标签内的任何内容都可以在子模板中被覆盖。
<!-- templates/base.html -->
<header>
<a href="/">Home</a> |
<a href="/about">About</a>
</header>
{% block content %}{% endblock %}[extends](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#extends) 标签允许我们通过指定父模板来建立模板之间的父子关系。将其添加到 home.html 和 about.html 模板的顶部。然后使用 {% [block](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#block) content %} 和 {% endblock %} 标签定义子模板内容。
<!-- templates/home.html -->
{% extends "base.html" %}
{% block content %}
<h1>Company Homepage</h1>
<p>The current date and time is: {% now "DATETIME_FORMAT" %}</p>
<p>There are {{ inventory_list|length }} items of inventory.
<ul>
{% for item in inventory_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<p>{{ greeting|title }}</p>
{% comment %}Add more content here!{% endcomment %}
{% endblock %}<!-- templates/about.html -->
{% extends "base.html" %}
{% block content %}
<h1>Company About Page</h1>
<p>The company address is {{ contact_address }} and the phone number is
{{ phone_number }}.</p>
{% endblock %}在浏览器中刷新每个网页以查看结果:
!带基础模板的公司首页
!带基础模板的公司关于页面
每个页面现在都包含 base.html 中的页眉,上面有首页和关于页面的导航链接。
命名 URL
经验丰富的 Web 开发者可能已经注意到我们当前页面链接方式的一个问题。我们在 views.py 和 urls.py 文件中硬编码了 URL 路径。在每个地方,我们为首页指定了 /,为关于页面指定了 about/。如果我们在一个地方更改了 URL 路径而没有在其他地方更改,会发生什么?我们会得到 404 页面未找到的错误。
Django 非常重视在单一位置定义逻辑的理念。在这种情况下,我们希望只在一个地方引用 URL 及其关联视图。为此,我们可以为 URL 添加一个 names/#naming-[url](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#url)-patterns)。[path()](https://docs.djangoproject.com/en/5.0/ref/urls/#path) 函数接受以下参数:path(route, [view](https://docs.djangoproject.com/en/5.0/ref/class-based-views/base/#django.views.generic.base.View.as_view), kwargs=None, [name](https://docs.djangoproject.com/en/5.0/topics/http/urls/#naming-url-patterns)=None)。默认情况下,kwargs 和 name 设置为 None,但我们可以在这里更新 name。
# pages/urls.py
from django.urls import path
from .views import home_page_view, AboutPageView
urlpatterns = [
path("about/", AboutPageView.as_view(), name="about"), # 新增
path("", home_page_view, name="home"), # 新增
]现在,每当我们想要引用特定的 URL 路径时,都可以通过内置的 [url](https://docs.djangoproject.com/en/5.0/ref/templates/builtins/#url) 模板标签,在模板中使用命名 URL。用下面的代码更新 base.html 文件。
<!-- templates/base.html -->
<header>
<a href="{% url 'home' %}">Home</a> |
<a href="{% url 'about' %}">About</a>
</header>
{% block content %}{% endblock %}如果你在浏览器中刷新网站,两个页面及其链接和以前一样工作。URL 路径现在只在一个位置设置——在 urls.py 文件中。命名 URL 使你的项目更容易维护和修改,因为 URL 模式的更改不需要在代码的多个地方进行修改。这是一个应该在所有 Django 项目中采用的最佳实践。
测试
在上一章中,我们为每个网页编写了一个单元测试,检查它是否返回 HTTP 200 状态码。让我们先快速回顾一下,然后为网站添加更稳健的测试。用下面的代码更新 pages/tests.py 文件:
# pages/tests.py
from django.test import SimpleTestCase
class HomepageTests(SimpleTestCase):
def test_url_exists_at_correct_location(self):
response = self.client.get("/")
self.assertEqual(response.status_code, 200)
class AboutpageTests(SimpleTestCase):
def test_url_exists_at_correct_location(self):
response = self.client.get("/about/")
self.assertEqual(response.status_code, 200)然后,按 Control+c 退出本地 Web 服务器,在命令行中输入 python manage.py test 来运行测试。
(.venv) $ python manage.py test
Found 2 test(s).
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.003s
OK到目前为止一切顺利。与上一章的个人网站相比,公司网站有什么变化?现在我们每个 URL 路由都有 URL 名称,所以我们应该检查它们是否按预期工作。我们可以使用方便的 Django 工具函数 reverseresolvers/#reverse)。它不会去访问 URL 路径,而是查找 URL 名称。通常,硬编码 URL 是一个坏主意,尤其是在模板中。我们可以通过使用 reverse 来避免这种情况。
打开文本编辑器中现有的 pages/tests.py 文件,添加以下代码:
# 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)
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)顶部我们导入了 SimpleTestCase(因为我们没有使用数据库),然后导入了 reverseresolvers/#reverse) 函数。有两个测试类分别对应每个网页。HomepageTests 检查首页在 / 处返回 200 状态码,然后检查对命名 URL "home" 调用 reverse 是否也做同样的事情。AboutpageTests 类中对关于页面的两个测试模式重复了同样的操作。
运行测试以确认它们正确工作。
(.venv) $ python manage.py test
Found 4 test(s).
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK我们已经测试了 URL 位置和名称,但没有测试模板。让我们确保每个页面使用了正确的模板 home.html 和 about.html,并且它们分别包含预期的文本 <h1>Company Homepage</h1> 和 <h1>Company About Page</h1>。我们可以使用 [assertTemplateUsed](https://docs.djangoproject.com/en/5.0/topics/testing/tools/#django.test.SimpleTestCase.assertTemplateUsed) 和 [assertContains](https://docs.djangoproject.com/en/5.0/topics/testing/tools/#django.test.SimpleTestCase.assertContains) 来实现这一点。
# 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>Company 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>Company About Page</h1>")最后一次运行测试以检查我们的新工作。所有测试都应该通过。
(.venv) $ python manage.py test
Found 8 test(s).
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 8 tests in 0.006s
OK有经验的程序员可能会注意到我们的测试代码重复性很高。例如,我们为全部八个测试都设置了 response。一般来说,遵循 DRY(Don’t Repeat Yourself)编码风格是个好主意,但单元测试在独立且高度详细的情况下效果最好。随着测试套件的扩展,出于性能原因,将多个断言合并到较少数量的测试中可能更有意义。
我们将来会做更多的测试,特别是当我们开始使用数据库时。目前,重要的是要看到每次向 Django 项目添加新功能时添加测试是多么容易和重要。
Git 和 GitHub
是时候用 Git 跟踪我们的更改并将它们推送到 GitHub 了。我们首先初始化目录并检查更改的状态。
(.venv) $ git init
(.venv) $ git status然后,创建一个 .gitignore 文件,指示 Git 不要跟踪哪些内容。我们将关注三个方面:包含虚拟环境的 .venv 目录、包含编译字节码的 __pycache__ 目录以及数据库文件 db.sqlite3。
.venv/
__pycache__/
db.sqlite3
下一步是创建一个 requirements.txt 文件,列出虚拟环境中的内容。
(.venv) $ pip freeze > requirements.txt
(.venv) $ git status最后一步是再次运行 git status 确认 requirements.txt 被包含在内,而 .gitignore 文件中的三个项目被忽略。然后,添加所有预期的文件和目录,并附上一个初始提交信息。
(.venv) $ git status
(.venv) $ git add -A
(.venv) $ git commit -m "initial commit"在 GitHub 上创建一个名为 company-website 的新仓库,确保选择”Private”单选按钮。然后点击”Create repository”按钮。
在下一页上,滚动到”…or push an existing repository from the command line”处。将那里的两条命令复制粘贴到你的终端中。
命令看起来应该像下面这样,只是用户名 wsvincent 会被替换为你的 GitHub 用户名。
(.venv) $ git remote add origin https://github.com/wsvincent/company-website.git
(.venv) $ git branch -M main
(.venv) $ git push -u origin main结论
恭喜你构建并部署了第三个 Django 项目!这一次,我们同时使用了基于函数的视图和通用基于类的视图来构建网站。我们引入了模板继承、命名 URL,并添加了更高级的测试。本章的完整源代码可在 GitHub 上找到,供你参考。在下一章中,我们将转向第一个基于数据库的项目——一个留言板网站,并见证 Django 真正大放异彩的地方。