作者:HelloGitHub-追梦人物

文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库

为了防止博客首页展示的文章过多以及提升加载速度,可以对文章列表进行分页展示。不过这需要比较多的文章才能达到分页效果,但本地开发时一般都只有几篇测试文章,如果一篇篇手工添加将会非常麻烦。

解决方案是我们可以写一个脚本,自动生成任意数量的测试数据。脚本写好后,只需运行脚本就可以往数据库填充大量测试数据。脚本就是一段普通的 Python 代码,非常简单,但是通过这个脚本你将学会如何在 django 外使用 ORM,而不仅仅在 django 应用的内部模块使用。

脚本目录结构

一般习惯于将项目有关的脚本统一放在项目根目录的 scripts 包中,当然这只是一个惯例,你也可以采用自己觉得合理的目录结构,只要保证这个包所在目录能够被 Python 找到。

依据惯例,我们博客项目中脚本的目录结构如下:

HelloDjango-blog-tutorial\     blog\     blogproject\     ...     scripts\         __init__.py         fake.py         md.sample

其中 fake.py 是生成测试数据的脚本,md.sample 是一个纯文本文件,内容是用于测试 Markdown 的文本。

使用 Faker 快速生成测试数据

博客文章包含丰富的内容元素,例如标题、正文、分类、标签。如果手工输入这些相关元素的文本会非常耗时,我们将借助一个 Python 的第三方库 Faker 来快速生成这些测试用的文本内容。Faker 意为造假工厂,顾名即可思义。

首先安装 Faker:

$ pipenv install Faker

Faker 通过不同的 Provider 来提供各种不同类型的假数据,我们将在下面的脚本中讲解它的部分用法,完整的用法可以参考其官方文档

批量生成测试数据

现在我们来编写一段 Python 脚本用于自动生成博客测试数据。思路非常简单,博客内容包括作者、分类、标签、文章等元素,只需依次生成这些元素的内容即可。当然为了使脚本能够正常运行,很多细节需要注意,我们会对需要注意的地方进行详细讲解。

先来看脚本 fake.py 开头的内容:

import os import pathlib import random import sys from datetime import timedelta  import django import faker from django.utils import timezone  # 将项目根目录添加到 Python 的模块搜索路径中 back = os.path.dirname BASE_DIR = back(back(os.path.abspath(__file__))) sys.path.append(BASE_DIR)

这一段很简单,只是导入一些会用到的模块,然后通过脚本所在文件找到项目根目录,将根目录添加到 Python 的模块搜索路径中,这样在运行脚本时 Python 才能够找到相应的模块并执行。

接下来是脚本的逻辑,先看第一段:

if __name__ == '__main__':     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blogproject.settings.local")     django.setup()      from blog.models import Category, Post, Tag     from comments.models import Comment     from django.contrib.auth.models import User

这是整个脚本最为重要的部分。首先设置 DJANGO_SETTINGS_MODULE 环境变量,这将指定 django 启动时使用的配置文件,然后运行 django.setup() 启动 django。这是关键步骤,只有在 django 启动后,我们才能使用 django 的 ORM 系统。django 启动后,就可以导入各个模型,以便创建数据。

接下来的逻辑就很简单了,不断生成所需的测试数据即可,我们来一段一段地看:

    print('clean database')     Post.objects.all().delete()     Category.objects.all().delete()     Tag.objects.all().delete()     Comment.objects.all().delete()     User.objects.all().delete()

这一段脚本用于清除旧数据,因此每次运行脚本,都会清除原有数据,然后重新生成。

    print('create a blog user')     user = User.objects.create_superuser('admin', 'admin@hellogithub.com', 'admin')      category_list = [