一、设置项目"学习笔记"的样式
之前,我们特意一直专注于项目"学习笔记"的功能,没有考虑样式设置的问题。这是一种不错的开发方法,因为能正确运行的应用程序才是有用的。应用程序能够正确运行之后,外观就显得很重要了,因为漂亮的应用程序才能吸引用户。
本节将安装应用程序 django-bootstrap5,并将其添加到项目"学习笔记"中。然后使用它来设置这个项目中各个页面的样式,确保页面的外观一致。
1. 应用程序 django-bootstrap5
下面使用 django-bootstrap5 将 Bootstrap 集成到项目"学习笔记"中。这个应用程序会下载必要的 Bootstrap 文件,并将它们放到项目的合适位置上,让你能够在项目的模板中使用样式设置指令。
为了安装 django-bootstrap5,在活动的虚拟环境中执行如下命令:
python
pip install django-bootstrap5
接下来,需要将 django-bootstrap5 添加到 settings.py 的INSTALLED_APPS 中:
python
INSTALLED_APPS = [
# 添加我的应用
'learning_logs',
'accounts',
# 第三方应用程序
'django_bootstrap5'
]
2. 使用 Bootstrap 设置项目"学习笔记"的样式
Bootstrap 包含大量样式设置工具,还提供了大量模板,用于设置项目的总体风格。对于 Bootstrap 初学者来说,模板比样式设置工具用起来容易得多。要查看 Bootstrap 提供的模板,可访问其官网主页并单击 Examples。我们将使用模板 Navbar static,它提供了简单的顶部导航栏以及用于放置页面内容的容器。
3. 修改 base.html
我们需要修改模板 base.html,以使用前述 Bootstrap 模板。这里将分五步逐步修改 base.html。这个文件很大,可以直接从配套的源代码文件中复制过来。即便复制了这个文件,也应仔细阅读接下来的几小节,弄明白都做了哪些修改。
- 定义 HTML 头部
对 base.html 所做的第一个修改是,在其中定义 HTML 头部。我们将添加一些代码,以便能够在模板中使用 Bootstrap。此外,还要给页面添加标题。请删除 base.html 的全部代码,并输入如下代码:
base.html
html
<!--编写的 HTML 文档-->
<!DOCTYPE html>
<!--首先,将这个文件声明为使用英语-->
<html lang="en">
<!--HTML 文件分为两大部分:头部(head)和主体(body)。在这个文件中,头部始于起始标签 <head>-->
<head >
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- HTML 文件的头部不包含任何页面内容,而只向浏览器提供正确显示页面所需的信息。这里包含一个<title> 元素-->
<title>Learning Log</title>
<!-- 在头部末尾,加载 django-bootstrap5 提供的模板标签集 -->
{% load django_bootstrap5 %}
{% bootstrap_css %}
{% bootstrap_javascript %}
</head>
- 定义导航栏
定义页面顶部导航栏的代码很长,因为需要同时支持较窄的手机屏幕和较宽的台式机显示器。
下面是导航栏定义代码的开头:
base.html
html
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'learning_logs:index' %}">
Learning Log
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarCollapse" aria-controls="navbarCollapse"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'learning_logs:topics' %}">
Topics
</a>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock content %}
</body>
- 添加用户账户链接
还需要添加与用户账户相关的链接。我们先来添加与账户相关的链接,再添加注销表单。
对文件 base.html 做如下修改:
html
<ul class="navbar-nav ms-auto mb-2 mb-md-0">
{% if user.is_authenticated %}
<li class="nav-item">
<span class="navbar-text me-2">Hello, {{ user.username }}.</span>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:register' %}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:login' %}">Log in</a>
</li>
{% endif %}
</ul>
- 在导航栏中添加注销表单
我们将其放在了 base.html 的末尾。下面将其放在一个更好的地方------导航栏中:
base.html
html
{% if user.is_authenticated %}
<form action="{% url 'accounts:logout' %}" method='post'>
{% csrf_token %}
<button name='submit' class='btn btn-outline-secondary btn-sm'>
Log out
</button>
</form>
{% endif %}
- 定义页面的主要部分
base.html 的余下部分包含页面的主要部分:
base.html
html
<main class="container">
<div class="pb-2 mb-2 border-bottom">
{% block page_header %}{% endblock page_header %}
</div>
<div>
{% block content %}{% endblock content %}
</div>
</main>
上面代码综合如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Learning Log</title>
{% load django_bootstrap5 %}
{% bootstrap_css %}
{% bootstrap_javascript %}
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'learning_logs:index' %}">
Learning Log
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarCollapse" aria-controls="navbarCollapse"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'learning_logs:topics' %}">
Topics
</a>
</li>
</ul>
<ul class="navbar-nav ms-auto mb-2 mb-md-0">
{% if user.is_authenticated %}
<li class="nav-item">
<span class="navbar-text me-2">Hello, {{ user.username }}.</span>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:register' %}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:login' %}">Log in</a>
</li>
{% endif %}
</ul>
{% if user.is_authenticated %}
<form action="{% url 'accounts:logout' %}" method='post'>
{% csrf_token %}
<button name='submit' class='btn btn-outline-secondary btn-sm'>
Log out
</button>
</form>
{% endif %}
</div>
</div>
</nav>
<main class="container">
<div class="pb-2 mb-2 border-bottom">
{% block page_header %}{% endblock page_header %}
</div>
<div>
{% block content %}{% endblock content %}
</div>
</main>
</body>
</html>
4. 使用 jumbotron 设置主页的样式
下面使用 Bootstrap 元素 jumbotron 来修改主页。jumbotron 元素是一个大框,在页面中显得鹤立鸡群,通常用于在主页中呈现简要的项目描述和让用户采取行动的元素。
修改后的文件 index.html 如下所示:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% extends 'learning_logs/base.html' %}
{% block page_header %}
<div class="p-3 mb-4 bg-light border rounded-3">
<div class="container-fluid py-4">
<h1 class="display-3">Track your learning.</h1>
<p class="lead">Make your own Learning Log, and keep a list of the
topics you're learning about. Whenever you learn something new
about a topic, make an entry summarizing what you've learned.</p>
<a class="btn btn-primary btn-lg mt-1"
href="{% url 'accounts:register' %}">Register >></a>
</div>
</div>
{% endblock page_header %}
{% block content %}
<p>Learning Log helps you keep track of your learning, for any topic you're interested in.</p>
{% endblock content %}
</body>
</html>
5. 设置登录页面的样式
我们改进了登录页面的整体外观,但还未设置登录表单的样式。下面来修改文件 login.html,让表单的外观与页面的其他部分一致:
login.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% extends 'learning_logs/base.html' %}
{% load django_bootstrap5 %}
{% block page_header %}
<h2>Log in to your account.</h2>
{% endblock page_header %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form action="{% url 'accounts:login' %}" method='post'>
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="Log in" %}
</form>
{% endblock content %}
</body>
</html>
运行结果如下:

6. 设置页面 topics 的样式
下面来确保用于查看信息的页面也有合适的样式,首先来设置页面topics 的样式:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% extends 'learning_logs/base.html' %}
{% block page_header %}
<h1>Topics</h1>
{% endblock page_header %}
{% block content %}
<ul class="list-group border-bottom pb-2 mb-4">
{% for topic in topics %}
<li class="list-group-item border-0">
<a href="{% url 'learning_logs:topic' topic.id %}">
{{ topic.text }}
</a>
</li>
{% empty %}
<li class="list-group-item border-0">No topics have been added yet.</li>
{% endfor %}
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a>
{% endblock content %}
</body>
</html>
7. 设置页面 topic 中条目的样式
在页面 topic 中,我们将使用 Bootstrap 组件 card 来突出显示每个条目。card 是带灵活的预定义样式的嵌套 <div>,非常适合用于显示主题的条目:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% extends 'learning_logs/base.html' %}
{% block page_header %}
<h1>{{ topic.text }}</h1>
{% endblock page_header %}
{% block content %}
<p>
<a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a>
</p>
{% if entries %}
<ul class="list-group border-bottom pb-2 mb-4">
{% for entry in entries %}
<li class="list-group-item border-0">
<h4>
{{ entry.date_added|date:'M d, Y H:i' }}
<small><a href="{% url 'learning_logs:edit_entry' topic.id entry.id %}">Edit entry</a></small>
</h4>
<div>{{ entry.text|linebreaks }}</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no entries for this topic yet.</p>
{% endif %}
{% endblock content %}
</body>
</html>
运行结果如下:

二、部署"学习笔记"
至此,项目"学习笔记"的外观已经很专业了,下面将其部署到服务器上,让任何有互联网连接的人都能够使用它。我们将使用 Platform.sh,这是一个基于 Web 的平台,供我们管理 Web 应用程序的部署。我们将让"学习笔记"在 Platform.sh 上运行起来。
1. 注册 Platform.sh 账户
要注册账户,请访问 Platform.sh 官方主页,并单击 Free Trial 按钮。编写期间Platform.sh 提供了免费试用服务(free tier),不要求你提供信用卡。在试用期间,你可以部署应用程序和少量资源,这让你能够在在线环境中测试应用程序,进而决定是否要购买收费托管套餐。
2. 安装 Platform.sh CLI
要将项目部署到 Platform.sh 服务器上并对其进行管理,需要使用Platform.sh CLI(command lineinterface,命令行界面)中的工具。要安装该 CLI 的最新版本,可访问其文档 Command line interface (CLI),并根据你使用的操作系统按相应的说明做。
在大多数系统中,可以在终端窗口中执行如下命令来安装 Platform.sh CLI:
python
curl -fsS https://platform.sh/cli/installer | php
执行这个命令后,要使用该 CLI,需要打开一个新的终端窗口
3. 安装 platformshconfig
还需安装一个名为 platformshconfig 的包。这个包可帮助我们监测项目运行在本地系统还是 Platform.sh 服务器上。为了安装这个包,可在活动的虚拟环境中执行如下命令:
python
pip install platformshconfig
4. 创建文件 requirements.txt
远程服务器需要知道项目"学习笔记"依赖于哪些包,因此我们将使用pip 生成一个文件,在其中列出这些包。为此,在活动的虚拟环境中执行如下命令:
python
pip freeze > requirements.txt
命令 freeze 让 pip 将项目中当前安装的所有包的名称都写入文件requirements.txt。请打开文件 requirements.txt,查看项目中安装的包及其版本:
requirements.txt
python
asgiref==3.5.2
beautifulsoup4==4.11.1
Django==4.1
django-bootstrap5==21.3
platformshconfig==2.4.0
soupsieve==2.3.2.post1
sqlparse==0.4.2
项目"学习笔记"依赖于 7 个特定版本的包,因此只在远程服务器有相应的环境时才能正确地运行。在这 7 个包中,有 3 个是我们手动安装的,其他4 个是作为依赖的包自动安装的。
5. 其他部署需求
在线服务器还需要另外两个包,它们用于为生产环境中的项目提供服务,因为在生产环境中,可能有很多用户同时发出请求。
在 requirements.txt 所在的目录中,新建一个文件并将其命名为requirements_remote.txt,然后在其中添加如下两个包:
6. 添加配置文件
所有托管平台都需要一些配置,这样项目才能在服务器上正确地运行。本节将添加如下三个配置文件。
- platform.app.yaml:这是项目的主配置文件,向 Platform.sh 指出了当前部署的项目是什么类型的以及该项目需要什么样的资源,还包含用于在服务器上构建项目的命令。
- platform/routes.yaml:这个文件定义了通往项目的路由。Platform.sh收到请求后,将根据这些配置将请求交给特定的项目。
- platform/services.yaml:这个文件定义了项目所需的其他服务。
这些都是 YAML(YAML Ain't Markup Language,YAML 不是标记语言)文件。YAML 是一种旨在用于编写配置文件的语言,无论是人还是计算机都能轻松地读取。你可以手动编写或修改典型的 YAML 文件,计算机也能够读取并准确无误地解读这种文件。
- 配置文件 .platform.app.yaml
个配置文件是最长的,因为它控制着整个配置过程。我们将分几部分进行介绍。你既可以在文本编辑器中手动输入它,也可以从本书的源代码文件中找到它。
下面是文件 .platform.app.yaml 的第一部分,应将该文件存储在manage.py 所在的目录中:
python
name: "ll_project"
type: "python:3.10"
relationships:
database: "db:postgresql"
# 应用程序被暴露到网上时使用的配置
web:
upstream:
socket_family: unix
commands:
start: "gunicorn -w 4 -b unix:$SOCKET ll_project.wsgi:application"
locations:
"/":
passthru: true
"/static":
root: "static"
expires: 1h
allow: true
# 应用程序的永久性磁盘的大小(单位为 MB)
disk: 512
# 设置用于读写日志的本地挂载
mounts:
"logs":
source: local
source_path: logs
# 在应用程序生命周期的不同时间点执行的钩子(hook)
hooks:
build: |
pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_remote.txt
mkdir logs
python manage.py collectstatic
rm -rf logs
deploy: |
python manage.py migrate
- 配置文件 routes.yaml
路由(route)指的是请求在被服务器处理的过程中经过的路径。Platform.sh 需要知道应将收到的请求发送到哪里。
在 manage.py 所在的目录中新建一个文件夹,并将其命名为.platform(不要遗漏开头的句点)。在这个文件夹中新建一个文件,将其命名为 routes.yaml,并在其中输入如下内容:
python
"https://{default}/":
type: upstream
upstream: "ll_project:http"
"https://www.{default}/":
type: redirect
to: "https://{default}/"
这个文件确保 URL 形如 https://project_url.com 和www.project_url.com 的请求都将被路由到同一个地方。
- 配置文件 services.yaml
这是最后一个配置文件,它指定了项目运行所需的服务。将这个文件与 routes.yaml 一起保存到目录 .platform/ 中:
platform/services.yaml
7. 为部署到 Platform.sh 而修改 settings.py
现在需要在 settings.py 末尾添加一个片段,在其中指定一些Platform.sh 环境设置:
python
from pathlib import Path
from platformshconfig import Config
config = Config()
if config.is_valid_platform():
# 添加 Platform.sh 域名到允许的 host
ALLOWED_HOSTS.append('.platformsh.site')
# 设置静态文件根目录
if config.appDir:
STATIC_ROOT = Path(config.appDir) / 'static'
# 设置 Django 的 SECRET_KEY
if config.projectEntropy:
SECRET_KEY = config.projectEntropy
# 仅在运行而非构建时配置数据库
if not config.in_build():
db_settings = config.credentials('database')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': db_settings['path'],
'USER': db_settings['username'],
'PASSWORD': db_settings['password'],
'HOST': db_settings['host'],
'PORT': db_settings['port'],
},
}
8. 使用 Git 跟踪项目文件
使用 Git 意味着在尝试实现新功能时无须担心破坏项目。在将项目部署到服务器上时,需要确保部署的是可行版本。
- 安装 Git
你的系统中,可能已经安装了 Git。要确定是否安装了 Git,可打开一个新的终端窗口,并在其中执行命令 git --version:

- 配置 Git
Git 跟踪是谁修改了项目,即便项目由一个人开发也是如此。为了进行跟踪,Git 需要知道你的用户名和电子邮箱地址。因此,你必须提供用户名,但对于练习项目,可随便伪造一个电子邮箱地址:

- 忽略文件
无须让 Git 跟踪项目中的每个文件,因此我们让它忽略一些文件。在manage.py 所在的文件夹中创建一个名为 .gitignore 的文件(请注意,这个文件名以句点打头且不包含扩展名),并在其中输入如下代码:
python
ll_env/
__pycache__/
*.sqlite3
- 提交项目
我们需要为"学习笔记"初始化一个 Git 仓库,将所有必要的文件都加入进来,并提交项目的初始状态,如下所示:


9. 在 Platform.sh 上创建项目
当前,项目"学习笔记"虽然还运行在本地系统上,但已经经过了配置,能够在远程服务器上正确地运行。下面使用 Platform.sh CLI 在远程服务器上新建一个项目,再将项目"学习笔记"推送到该服务器上。
打开一个终端窗口,切换到目录 learning_log/,并执行如下命令:
python
platform login
下面来创建一个项目。输出很多,我们将分几部分来介绍创建过程。首先,执行命令 create:
python
platform create
python
ll_project
python
us-3.platform.sh
10. 推送到 Platform.sh
最后一步是将代码推送到远程服务器上,然后就可以查看项目的在线版本了。请执行如下命令:
python
platform push
11. 查看线上项目
完成推送工作后,就可以打开项目了:
python
platform url