自己动手写动态博客(二)

缘起

2019年,我写了一个动态博客,并发表了一篇博客《自己动手写动态博客》,主要介绍了基于 Quasar 和 Express 的动态博客框架。但是后面这个动态博客被废弃了,原因是多方面的。一方面项目的部署没有基于 Docker,导致维护起来比较复杂。另一方面,该项目是前后端分离的,文章内容通过接口进行获取,再加上没有 SSR,所以就算想要提交搜索引擎,也很难进行搜索。此外,项目缺乏一个高可用性的后端管理平台。再加上当时网页设计水平有限,很多涉及其实比较反人类,因此最终还是继续使用了基于 GitHub Pages 的静态博客。

其实在做这个动态博客之前,并没有真的打算做一个博客出来,只是为了试一下 django-vditor 这个包,甚至项目文件夹名称都是 test-django-vditor,因为 Vditor 差不多已经是前端最强 Markdown 编辑器了。倒是初衷和博客有一定关系。2020年初设计了 GWmodel Lab 的主页,内容很全。由于网页是部署在群晖的 Web 服务器上,限制很大,所以项目虽然是前后端分离,但是总体上是一个静态网页,所有的 API 全都保存成了 JSON 文件。但是维护起来非常麻烦。这个主页一共分为了三个仓库:React 前端、Markdown 内容、Django 管理平台。当需要增加内容时,先在写好 Markdown 内容,使用 Git 进行版本管理,然后在 Django 中向数据库中添加相应的项目,再将接口响应内容保存成 JSON 文件,最后将 React 前端和内容以及接口相应内容部署到 Web 服务器上。当我还在实验室的时候,整个流程已经被打通,更新还算方便。但是交接给师弟的时候,想要讲清楚整个流程,就非常难了。

那么有没有一种比较方便的管理方法呢?有,其实只要找到一种方法,让 Django 直接可以输出整个网页,然后使用一些脚本将这些网页保存成 HTML 文件,再发布到网页服务器上就可以了。这个过程甚至可以让 Django 自己完成。配合 Django 的管理平台,更新内容就不复杂了。进一步地,如果要对搜索引擎友好,可以抛弃前后端分离的思路,反而使用 Django 的模板引擎渲染页面。

基于以上思路,我做了这个动态博客,就当作实验室主页的一个小 Demo。

框架

这个动态博客的框架非常简单,就是 Django + Bootstrap,没有 MVVM 框架,没有前后端分离,以至于写的时候仿佛回到了自己 2016 年用 Bootstrap 写网页的时代。

但是这个框架对于个人博客来讲,就显得很方便了。毕竟个人博客的项目复杂度不高,没有使用前端框架的必要,也没有前后端分离的必要,事实上,前后端分离反而会带来很多其他麻烦。而且 Django 现在的功能已经非常强大了,很多功能(例如图片上传、权限管理)只需要增加一些配置就可以解决,其管理平台更是可以让我们少些很多代码。经过几年的发展,Bootstrap 使用起来也很方便了,而且样式并不过时,也很简洁,很适合个人博客。

下面介绍一些具体的细节。

数据库

似乎每一个教关系数据库的教程,都会用博客作为案例场景进行介绍。这是因为这个场景非常简单,但是涉及了一对多、多对多两种关系。通常,会有四张表:文章(Post)、分类(Category)、标签(Tag)和作者(Author)。本框架暂时省略了作者表,因为目前来说作者只有我一个人。数据库中主要的表和它们的关系如下图所示。

其中几个类的具体情况是

可以说这真的是最精简版的博客数据库了。当然数据库中实际存在的还是有 Django 自带的权限表 Group 和 User。为了使用 Vditor,实际实现时还是要把 TextField 替换成 VditorTextField,才能在 Django Admin 中使用 Vditor 进行编辑。

视图和模板

视图这部分没什么好说的,主要是以下几个视图:

  • Post 的增删查改
  • User 的登入登出
  • Home

登入登出功能主要是限制 Post 增删改的权限。但是如果不要求在前端进行文章操作,完全可以不要登入登出和 Post 的增删改操作(比较适合导出成静态页面)。

主页 Home 的渲染是根据 Profile 中关联的第一个 User 表中用户的记录。由于这个项目在使用 Docker 部署的时候,必然会创建一个超级用户,这个超级用户就是作为第一个用户存在的。Home 中最左侧的介绍以及中间的头像,就是从数据库中取出这个超级用户的相应记录进行渲染的。

模板几乎与视图一一对应,只不过为了避免写重复的代码,将模板进行了分解,使用 Django 提供的 extends 关键词进行模板扩展。主要继承关系如下所示。

日后还可以在此基础上添加其他的模块,例如相册等。

部署

该项目提供了 Dockerfile 用于构建 Docker 镜像,可以直接使用 Docker 部署。事实上,该项目就是利用 VSCode 的远程开发功能在 Docker 容器里面开发的。同时仓库中也提供了一个 docker-compose 配置样例,可以直接部署。下图是在服务器上部署后的效果。

相应的 docker-compose 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
version: '3.8'

services:
app:
image: hpdell/myzone-django:latest
volumes:
- upload-data:/code/uploads
ports:
- "8080:8000"
depends_on:
- db
links:
- "db:db"
restart: unless-stopped
environment:
- DJANGO_SUPERUSER_USERNAME=
- DJANGO_SUPERUSER_EMAIL=
- DJANGO_SUPERUSER_PASSWORD=
- MYZONE_HOST=huyg.site

db:
image: postgres:latest
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_USER:
POSTGRES_DB:
POSTGRES_PASSWORD:

volumes:
postgres-data: null
upload-data: null

注意配置中将 uploads 文件夹(上传的图片所保存的位置)永久性保留了下来,这样每次代码更新,直接拉取最新镜像并重新部署容器即可(在 Protainer 中甚至只需要点点鼠标)。

结语

整个博客开发时间,满打满算可能有四天,就已经实现了绝大多数功能(有一些在文章中没有介绍,比如本地化、移动端适配),相比之前那个动态博客,开发难度降低了很多,而且可扩展性也很强。这得益于 Django 的强大功能,以及最简化的项目框架,这样我觉得没有选择最火热的 Vue/React 和前后端分离框架是一个非常正确的决定。这样我想起一段往事。

去年我在进行毕设答辩的时候,有一个评委老师问我这样一个问题:“你觉得模型是越复杂越好,还是越简单越好?”我给出的回答是:“模型的复杂度要与实际问题相匹配。”

虽然我不知道这个回答有没有让老师满意,但在开发做项目时,我觉得也是同样的情况,用的技术栈也不是越强大越好,而是要和项目内容相匹配。用一些简化的技术去开发复杂的项目,难度一定会越来越大;而用一些太过强大的技术开发简单的项目,反而会带来很多不必要的麻烦。但是,这并不是说 Django 模板系统不强大,只是基于模板的渲染系统在项目规模更大时会变得比较麻烦,此时采用前后端分离的框架会更好。

当然,这个博客还有一些功能有待完善:

  • 草稿功能。思路是在 Post 中增加一个 Draft 字段来表示是不是草稿,前端再增加一个草稿箱的列表页面。
  • 自动保存。思路是借助 Vditor 自带的缓存功能实现。
  • 退出提醒。退出编辑页面时提示用户数据可能没有保存,避免文稿丢失。

希望这个博客能够稳定运行更长的时间。

感谢您的阅读,本文由 HPDell 的个人博客 版权所有。如若转载,请注明出处:HPDell 的个人博客(http://hpdell.github.io/编程/dynamic-blog-v2/
Windows 创建符号链接的命令 mklink
原神中为什么暴击暴伤比为1:2最好?