Django中如何实现启动初始化数据库、关闭自动销毁库的开发服务?
问题描述
我在开发后端的同时也在开发前端,需要向后端服务发送若干REST请求。
目前有几种可选方案:我可以在前端使用mocks,或是fake JSON server,但该方案存在以下弊端:
- 需要对现有后端服务已实现的逻辑进行重建模
- 在fake JSON server上处理认证逻辑的体验较差
- 如果选择mock和单元测试方案,需要编写大量样板代码
我需要的逻辑已经在现有Django项目中全部实现,因此我期望实现以下效果:
- 运行开发服务
- 创建一个全新的数据库
- 注入初始数据:包括测试用的虚假用户、帖子等测试数据
- 服务运行期间可对前端项目进行测试
- 触发终止信号(CTRL+C)
- 自动优雅删除步骤2中创建的数据库
- 关闭服务程序
我目前使用pytest和pytest-django,这两个工具搭建测试环境时刚好会执行上述流程,我想知道是否可以手动实现该效果。
运行环境
- Python 3.9
- Django 2.2
解决方案
方案1:自定义Django管理命令(推荐,无需额外依赖)
你可以直接写一个Django自定义命令实现全流程,步骤如下:
- 先准备测试数据
在项目根目录新建fixtures文件夹,把你需要的测试用户、帖子等数据导出为fixture文件:
python manage.py dumpdata auth.User your_app_name.Post --indent 2 > fixtures/test_init.json
如果不想导出现有数据,也可以直接写Python脚本来生成虚假数据,配合Faker库使用更方便。
- 编写自定义命令
在你任意一个注册过的Django App下,新建management/commands目录,目录下新增两个文件:__init__.py(空文件即可)和run_temp_server.py,写入以下代码:
import os import signal import tempfile from django.core.management import call_command from django.core.management.base import BaseCommand from django.conf import settings class Command(BaseCommand): help = "启动带临时数据库和测试数据的开发服务,退出后自动销毁数据库" def handle(self, *args, **options): # 1. 创建临时SQLite数据库(如果用MySQL/PostgreSQL可修改为创建临时库逻辑) temp_db = tempfile.NamedTemporaryFile(suffix='.sqlite3', delete=False) temp_db_path = temp_db.name temp_db.close() # 覆盖DATABASE配置 original_db = settings.DATABASES['default']['NAME'] settings.DATABASES['default']['NAME'] = temp_db_path # 注册退出信号处理 def cleanup(signum, frame): self.stdout.write(self.style.WARNING("收到终止信号,开始清理资源...")) # 删除临时数据库 if os.path.exists(temp_db_path): os.unlink(temp_db_path) settings.DATABASES['default']['NAME'] = original_db self.stdout.write(self.style.SUCCESS("临时数据库已删除,服务关闭")) exit(0) signal.signal(signal.SIGINT, cleanup) signal.signal(signal.SIGTERM, cleanup) # 2. 执行迁移 self.stdout.write(self.style.NOTICE("正在执行数据库迁移...")) call_command('migrate') # 3. 加载初始测试数据 self.stdout.write(self.style.NOTICE("正在注入初始测试数据...")) call_command('loaddata', 'fixtures/test_init.json') # 如果你用Python脚本生成数据,在这里调用你的生成逻辑即可 # 4. 启动开发服务 self.stdout.write(self.style.SUCCESS(f"临时服务已启动,临时数据库路径: {temp_db_path}")) self.stdout.write(self.style.SUCCESS("按CTRL+C终止服务并清理资源")) call_command('runserver', '--noreload')
- 直接运行命令即可使用
python manage.py run_temp_server
启动后就是正常的开发服务,所有数据存在临时库,按CTRL+C退出时会自动删除临时数据库,不会影响你正常的开发库数据。
方案2:基于pytest实现(适配你现有pytest环境)
因为你已经在用pytest和pytest-django,可以直接写一个pytest启动脚本复用pytest的测试环境逻辑:
- 在项目根目录新建
run_test_server.py,写入以下代码:
import pytest from django.core.management import call_command def run_server(): # pytest会自动创建测试数据库、应用迁移 # 你可以把数据初始化逻辑写在session级别的fixture里 call_command('runserver', '--noreload') if __name__ == "__main__": pytest.main([ "-s", "--no-header", "--tb=short", "-q", __file__, ])
- 在
conftest.py里加一个session级别的fixture注入初始数据:
import pytest from django.contrib.auth.models import User from your_app.models import Post @pytest.fixture(scope="session", autouse=True) def init_test_data(django_db_setup, django_db_blocker): with django_db_blocker.unblock(): # 这里写你要生成的测试数据逻辑 User.objects.create_user(username="testuser", password="testpass123") Post.objects.create(title="测试帖子", content="测试内容")
直接运行python run_test_server.py即可,退出时pytest会自动销毁测试数据库。
注意事项
- 如果使用MySQL/PostgreSQL作为数据库,需要给你的数据库账号分配创建、删除数据库的权限,临时库名可以用随机字符串生成,退出时执行DROP DATABASE操作即可
- 上述方案默认关闭了runserver的自动重载功能,如果需要开启重载,需要把清理逻辑放到父进程处理,避免子进程退出时重复触发清理
内容的提问来源于stack exchange,提问作者Eray Erdin
相关产品推荐
相关产品推荐

