网站首页 > 技术文章 正文
作者:HelloGitHub-追梦人物
为了防止博客首页展示的文章过多以及提升加载速度,可以对文章列表进行分页展示。不过这需要比较多的文章才能达到分页效果,但本地开发时一般都只有几篇测试文章,如果一篇篇手工添加将会非常麻烦。
解决方案是我们可以写一个脚本,自动生成任意数量的测试数据。脚本写好后,只需运行脚本就可以往数据库填充大量测试数据。脚本就是一段普通的 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[3] 来快速生成这些测试用的文本内容。Faker 意为造假工厂,顾名即可思义。
首先安装 Faker:
$ pipenv install Faker
Faker 通过不同的 Provider 来提供各种不同类型的假数据,我们将在下面的脚本中讲解它的部分用法,完整的用法可以参考其官方文档[4]。
批量生成测试数据
现在我们来编写一段 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 = ['Python学习笔记', '开源项目', '工具资源', '程序员生活感悟', 'test category']
 tag_list = ['django', 'Python', 'Pipenv', 'Docker', 'Nginx', 'Elasticsearch', 'Gunicorn', 'Supervisor', 'test tag']
 a_year_ago = timezone.now() - timedelta(days=365)
 print('create categories and tags')
 for cate in category_list:
 Category.objects.create(name=cate)
 for tag in tag_list:
 Tag.objects.create(name=tag)
 print('create a markdown sample post')
 Post.objects.create(
 title='Markdown 与代码高亮测试',
 body=pathlib.Path(BASE_DIR).joinpath('scripts', 'md.sample').read_text(encoding='utf-8'),
 category=Category.objects.create(name='Markdown测试'),
 author=user,
 )
这个脚本没什么说的,简单地使用 django 的 ORM API 生成博客用户、分类、标签以及一篇 Markdown 测试文章。
 print('create some faked posts published within the past year')
 fake = faker.Faker() # English
 for _ in range(100):
 tags = Tag.objects.order_by('?')
 tag1 = tags.first()
 tag2 = tags.last()
 cate = Category.objects.order_by('?').first()
 created_time = fake.date_time_between(start_date='-1y', end_date="now",
 tzinfo=timezone.get_current_timezone())
 post = Post.objects.create(
 title=fake.sentence().rstrip('.'),
 body='\n\n'.join(fake.paragraphs(10)),
 created_time=created_time,
 category=cate,
 author=user,
 )
 post.tags.add(tag1, tag2)
 post.save()
这段脚本用于生成 100 篇英文博客文章。博客文章通常内容比较长,因此我们使用了之前提及的 Faker 库来自动生成文本内容。脚本逻辑很清晰,只对其中涉及的几个知识点进行讲解:
 fake = faker.Faker('zh_CN')
 for _ in range(100): # Chinese
 tags = Tag.objects.order_by('?')
 tag1 = tags.first()
 tag2 = tags.last()
 cate = Category.objects.order_by('?').first()
 created_time = fake.date_time_between(start_date='-1y', end_date="now",
 tzinfo=timezone.get_current_timezone())
 post = Post.objects.create(
 title=fake.sentence().rstrip('.'),
 body='\n\n'.join(fake.paragraphs(10)),
 created_time=created_time,
 category=cate,
 author=user,
 )
 post.tags.add(tag1, tag2)
 post.save()
这一段脚本和上一段几乎完全一样,唯一不同的是构造 Faker 实例时,传入了一个语言代码 zh_CN,这将生成中文的虚拟数据,而不是默认的英文。
 print('create some comments')
 for post in Post.objects.all()[:20]:
 post_created_time = post.created_time
 delta_in_days = '-' + str((timezone.now() - post_created_time).days) + 'd'
 for _ in range(random.randrange(3, 15)):
 Comment.objects.create(
 name=fake.name(),
 email=fake.email(),
 url=fake.uri(),
 text=fake.paragraph(),
 created_time=fake.date_time_between(
 start_date=delta_in_days, 
 end_date="now", 
 tzinfo=timezone.get_current_timezone()),
 post=post,
 )
 print('done!')
最后依葫芦画瓢,给前 20 篇文章(Post) 生成评论数据。要注意的是评论的发布时间必须位于被评论文章的发布时间和当前时间之间,这就是 delta_in_days = '-' + str((timezone.now() - post_created_time).days) + 'd' 这句代码的作用。
执行脚本
脚本写好了,在项目根目录执行下面的命令运行整个脚本:
$ pipenv run python -m scripts.fake
看到如下的输出说明脚本执行成功了。
clean database create a blog user create categories and tags create a markdown sample post create some faked posts published within the past year create some comments done!
运行开发服务器,访问博客首页可以看到生成的测试数据,是不是有点以假乱真的感觉?
现在,我们有了 200 多篇测试文章,用来测试分页效果就十分简单了,接下来让我们来实现功能完整的分页效果。
参考资料
[1]HelloGitHub-追梦人物: https://www.zmrenwu.com
[2]HelloGitHub-Team 仓库: https://github.com/HelloGitHub-Team/HelloDjango-blog-tutorial
[3]Faker: https://github.com/joke2k/faker
[4]官方文档: http://faker.rtfd.org/
『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源~
猜你喜欢
- 2024-09-09 分享一些你可能还没使用的 JavaScript 技巧
 - 2024-09-09 可视化搜索引擎和机器学习技术索引Python实例
 - 2024-09-09 Python 爬取张国荣最火的 8 首歌,60000 评论看完泪奔!
 - 2024-09-09 万字详文:超越 BERT 模型的 ELECTRA 代码解读
 - 2024-09-09 大受欢迎的Kubernetes:快速入门&进阶实战
 - 2024-09-09 首发|Clusterpedia 0.1.0 四大重要功能
 - 2024-09-09 NET开发者的HTTP交互新宠(豪门36夜:黑帝的替身新宠)
 - 2024-09-09 BGP路径属性:Origin和AS_PATH(bgp路由协议中origin属性)
 - 2024-09-09 如何修改容器时间而不改变宿主机时间?
 - 2024-09-09 VASP计算杂化能带详细步骤教程(vasp杂化泛函计算)
 
- 最近发表
 - 
- 聊一下 gRPC 的 C++ 异步编程_grpc 异步流模式
 - [原创首发]安全日志管理中心实战(3)——开源NIDS之suricata部署
 - 超详细手把手搭建在ubuntu系统的FFmpeg环境
 - Nginx运维之路(Docker多段构建新版本并增加第三方模
 - 92.1K小星星,一款开源免费的远程桌面,让你告别付费远程控制!
 - Go 人脸识别教程_piwigo人脸识别
 - 安卓手机安装Termux——搭建移动服务器
 - ubuntu 安装开发环境(c/c++ 15)_ubuntu安装c++编译器
 - Rust开发环境搭建指南:从安装到镜像配置的零坑实践
 - Windows系统安装VirtualBox构造本地Linux开发环境
 
 
- 标签列表
 - 
- cmd/c (90)
 - c++中::是什么意思 (84)
 - 标签用于 (71)
 - 主键只能有一个吗 (77)
 - c#console.writeline不显示 (95)
 - pythoncase语句 (88)
 - es6includes (74)
 - sqlset (76)
 - apt-getinstall-y (100)
 - node_modules怎么生成 (87)
 - chromepost (71)
 - flexdirection (73)
 - c++int转char (80)
 - mysqlany_value (79)
 - static函数和普通函数 (84)
 - el-date-picker开始日期早于结束日期 (76)
 - js判断是否是json字符串 (75)
 - c语言min函数头文件 (77)
 - asynccallback (87)
 - localstorage.removeitem (77)
 - vector线程安全吗 (73)
 - java (73)
 - js数组插入 (83)
 - mac安装java (72)
 - 无效的列索引 (74)
 
 
