使用 Django 项目中的 ORM 编写伪造测试数据脚本
文中所涉及的示例代码,已同步更新到 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 = [