接口测试平台后端开发笔记(CLY)
后端技术栈
python + Django + DjangoRestFramework + Celery + mysql + redis
一、后端环境
相关软件可以自行搜索CSDN或菜鸟教程进行安装
1、本地安装mysql数据库
https://www.runoob.com/w3cnote/windows10-mysql-installer.html?ivk_sa=1024320u
2、本地安装redis数据库
https://www.runoob.com/redis/redis-install.html
3、安装python3.10
https://www.runoob.com/python/python-install.html
4、安装pycharm
http://test.runoob.com/w3cnote/pycharm-windows-install.html
5、安装虚拟环境管理工具
推荐conda
6、安装Django
pip install django
二、后端接口模块说明
1、用户模块(使用django自带的用户模块)
- ##### 用户登录
- ##### 用户登录态管理(token管理)
- ##### 用户登录管理(账号创建和管理)
2、测试项目模块
- ##### 测试项目管理:项目增、删、查、改等功能
- ##### 项目的测试环境管理:环境的增、删、查、改等功能
- ##### 文件管理:文件上传和文件管理(测试的接口涉及到文件上传时,需要使用文件)
3、接口测试模块
- ##### 项目接口管理:接口的增、删、查、改功能
- ##### 接口用例管理:接口的增、删、查、改功能
- ##### 接口用例的运行
4、场景测试模块
- ##### 测试场景管理:业务流的增、删、查、改
- ##### 测试场景中的测试步骤:增、删、查、改
- ##### 测试场景的运行
5、测试任务模块
- ##### 测试任务的管理:测试任务的增、删、查、改
- ##### 测试任务的运行
- ##### 查看测试任务执行记录
- ##### 测试报告查看
6、定时任务模块
- ##### 管理定时任务:定时任务的增删查改
- ##### 定时任务的启用和关闭
7、bug管理模块
- ##### 提交bug
- ##### 获取bug列表
- ##### 查询bug详情
- ##### 修改bug状态
三、创建项目和初始配置
1、创建Django项目
# 或者直接使用pycharm创建django项目
django-admin startproject apiTestPlatform
2、安装项目依赖
# Django
pip install Django==4.2
# DRF框架
pip install djangorestframework==3.14.0
# mysql数据库操作
pip install mysqlclien
# 用例执行引擎
pip install ApiTestEngine
3、分模块创建django应用
# 创建用户应用
python manage.py startapp users
# 创建项目应用
python manage.py startapp TestProject
# 创建接口测试应用
python manage.py startapp TestInterface
# 创建业务流测试应用
python manage.py startapp TestScene
# 创建测试任务应用
python manage.py startapp TestTask
# 创建定时任务应用
python manage.py startapp TestCronjob
# 创建bug管理应用
python manage.py startapp TestBug
4、初始化项目配置
# 修改settings.py文件
# 1-数据库配置
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": 'test001',
"USER": 'root',
"PASSWORD": '123456',
"HOST": '127.0.0.1',
"PORT": 3306
}
}
# 2-配置时区
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
# 3-注册应用
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# 注册 drf 框架
"rest_framework",
# 注册项目应用
"users",
"TestProject",
"TestInterface",
"TestScene",
"TestTask",
"TestCronjob",
"TestBug",
]
5、创建用户
# 1-生成数据迁移文件
python manage.py makemigrations
# 2-执行数据迁移
python manage.py migrate
# 3-创建一个超级管理员
python manage.py createsuperuser
# 账号示例:
用户名:cly
邮箱:cly20230201@gmail.com
密码:admin123
6、启动项目
python manage.py runserver
点击网址,使用刚刚创建的账户登录进入
四、用户模块开发
1、登录接口
①接口信息
接口名称:/api/users/login/
请求方式:POST
参数格式:JSON
请求参数:
参数 | 变量名 | 类型 | 说明 | 是否必传 |
---|---|---|---|---|
用户名 | username | 字符串 | 用户名 | 是 |
密码 | password | 字符串 | 密码 | 是 |
请求示例:
{
"username": "cly",
"password": "1996ASzx929"
}
返回示例:
# 状态码:200
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbiI6InJlZnJlc2giLCJleHAiOjE2MTQ4NTIyODQsImp0aSI6IjkwNWEzOTdiYTQ0ODQ1OTRiZTU1MDI4NmJjNWJiZjIwIiwidXNlcl9pZCI6MX0.WktTD8vABca5nQ0c9RB-KNOsaV-E7_ziQnjezndRzkk",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbiI6ImFjY2VzcyIsImV4cCI6MTYxNDc2NjE4NCwianRpIjoiZDk2MjFmZjhkMWNjNGJhODlkNTExNTQw·YjdlMTQ5ZjQiLCJ1c2VyX2lkIjoxfQ.IcCRz9kxGlwKTfCeScwGsWEjhoxPBbP6_HT3TMwBZHM"
}
②功能开发
接口鉴权实现:
# 1-安装 djangorestframework-simplejwt
pip install djangorestframework - simplejwt
# 2-注册应用
INSTALLED_APPS = [
...
# 注册 jwt 应用
"rest_framework_simplejwt",
]
# 3-配置 rest_framework 中的鉴权方式
REST_FRAMEWORK = {
# 配置登录鉴权方式
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
# 4-token配置
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60), # 访问令牌的有效时间
"REFRESH_TOKEN_LIFETIME": timedelta(days=1), # 刷新令牌的有效时间
"ROTATE_REFRESH_TOKENS": False, # 若为True,则刷新后新的refresh_token有更新的有效时间
"BLACKLIST_AFTER_ROTATION": True, # 若为True,刷新后的token将添加到黑名单中,
"ALGORITHM": "HS256", # 对称算法:HS256 HS384 HS512 非对称算法:RSA
"SIGNING_KEY": SECRET_KEY,
"VERIFYING_KEY": None, # if signing_key, verifying_key will be ignore.
"AUDIENCE": None,
"ISSUER": None,
"AUTH_HEADER_TYPES": ("Bearer",), # Authorization: Bearer <token>
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", # if HTTP_X_ACCESS_TOKEN, X_ACCESS_TOKEN: Bearer <token>
"USER_ID_FIELD": "id", # 使用唯一不变的数据库字段,将包含在生成的令牌中以标识用户
"USER_ID_CLAIM": "user_id",
}
# 5-添加路由
path('api/users/login/', TokenObtainPairView.as_view(), name='login'), # 登录
③接口调试
打开postman调试
修改返回参数名
# 1-重写TokenObtainPairView
class LoginView(TokenObtainPairView):
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
except TokenError as e:
raise InvalidToken(e.args[0])
result = serializer.validated_data
result['token'] = result.pop('access')
return Response(serializer.validated_data, status=status.HTTP_200_OK)
# 2-更换路由配置
# path('api/users/login/', TokenObtainPairView.as_view(), name='login'), # 登录
path('api/users/login/', LoginView.as_view(), name='login'), # 登录
打开postman调试
2、刷新token接口
①接口信息
接口名称:/api/users/token/refresh/
请求方式:POST
参数格式:JSON
请求参数:
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
refresh | 是 | string | refresh_token |
返回示例:
# 状态码 200
{"access":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTQyMTU0LCJpYXQiOjE2NjMxNDEzMTYsImp0aSI6IjRjODY1MDAwZDNkODQ3ZTBiYTA2NmJjZWVkZmNiYTY0IiwidXNlcl9pZCI6MX0.W8o59kEsY3NsCYC3pCm8VRxD7wdf30CavFnWQJ5lJBE"}
②功能开发
直接使用 rest_framework_simplejwt 提供的刷新视图配置路由
path('api/users/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # 刷新token
③接口调试
后续的接口,都需要自行调试
3、校验token接口
①接口信息
接口名称:/api/users/token/verify
请求方式:POST
参数格式:JSON
请求参数:
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
token | 是 | string | refresh_token |
返回示例:
# 200 校验通过, 无响应体
# 401 校验失败,无效的token
{
"detail": "令牌无效或已过期",
"code": "token_not_valid"
}
②功能开发
直接使用 rest_framework_simplejwt 提供的校验视图配置路由
path('api/users/token/verify/', TokenVerifyView.as_view(), name='token_verify'), # 校验token
五、项目管理模块开发
从这里开始,需要自定义模型类、序列化器、视图集…
1-1测试项目模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
name | varchar | 否 | 项目名称 | |
leader | varchar | 否 | 项目负责人 | |
create_time | timestamp | 是 | 添加时间 |
②模型类创建
class Project(models.Model):
"""项目表"""
name = models.CharField(max_length=50, help_text='项目名称', verbose_name='项目名')
leader = models.CharField(max_length=50, help_text='负责人', verbose_name='负责人')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间')
def __str__(self):
return self.name
class Meta:
db_table = 'test_project'
verbose_name_plural = "测试项目表"
③数据迁移
py manage.py makemigrations
py manage.py migrate
④注册admin
@admin.register(TestProject)
class TestProjectAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'leader', 'create_time']
1-2接口说明
①接口1:获取测试项目列表
参数格式:JSON
# 接口地址:/api/testPro/projects/
# 请求方法:GET
# 响应示例:状态码 200
[
{
"id": 1,
"create_time": "2024-03-12T21:59:57.606147+08:00",
"name": "小小浆站",
"leader": "伦宇"
}
]
②接口2:获取测试项目详情
# 接口地址:/api/testPro/projects/${id}/
# 请求方法:GET
# 响应示例:状态码 200
{
"id": 1,
"create_time": "2024-03-12T21:59:57.606147+08:00",
"name": "小小浆站",
"leader": "伦宇",
}
③接口3:创建测试项目
# 接口地址:/api/testPro/projects/
# 请求方法:POST
# 请求示例:两个参数必填,值为字符串类型
{
"name": "小小浆站",
"leader": "伦宇"
}
# 响应示例:状态码 201
{
"id": 1,
"create_time": "2022-07-12T21:59:57.606147+08:00",
"name": "小小浆站接口自动化",
"leader": "lunyu"
}
④删除测试项目
# 接口地址:/api/testPro/projects/${id}/
# 请求方法:DELETE
# 响应示例:状态码 204
{
无数据
}
⑤修改测试项目
# 接口地址:/api/testPro/projects/${id}/
# 请求方法:PATCH
# 请求示例:两个参数非必填,值为字符串类型
{
"name": "小小浆站",
"leader": "伦宇"
}
# 响应示例:状态码 201
{
"id": 1,
"create_time": "2022-07-12T21:59:57.606147+08:00",
"name": "小小浆站接口自动化",
"leader": "lunyu"
}
1-3序列化器
class TestProjectSerializer(serializers.ModelSerializer):
"""测试项目序列化器"""
class Meta:
model = TestProject
fields = "__all__"
1-4视图集
class TestProjectViewSet(ModelViewSet):
"""测试项目视图集"""
queryset = TestProject.objects.all()
serializer_class = TestProjectSerializer
# token鉴权
permission_classes = [IsAuthenticated]
1-5注册路由
# 创建路由对象
router = routers.SimpleRouter()
# 注册测试项目路由
router.register(r'api/testPro/projects', TestProjectViewSet) # 测试项目
1-6接口调试
2-1测试环境模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 关联项目 | |
global_variable | json | 是 | {} | 全局变量 |
debug_global_variable | json | 是 | {} | 调试模式全局变量 |
db | json | 是 | {} | 数据库配置(这里列表?) |
host | varchar | 是 | 测试环境host地址 | |
headers | json | 是 | {} | 全局请求头配置 |
global_func | textField | 是 | 全局工具函数文件 | |
name | varchar | 否 | 测试环境名称 |
②模型类创建
class TestEnv(models.Model):
"""测试环境表"""
project = models.ForeignKey(TestProject, on_delete=models.CASCADE, help_text='项目id', verbose_name='项目id')
name = models.CharField(max_length=150, help_text='环境名称', verbose_name='环境名称')
global_variable = models.JSONField(default=dict, null=True, blank=True, help_text='全局变量', verbose_name='全局变量')
debug_global_variable = models.JSONField(default=dict, null=True, blank=True, help_text='debug模式全局变量', verbose_name='debug模式全局变量')
db = models.JSONField(default=list, null=True, blank=True, help_text='数据库配置', verbose_name='数据库配置')
host = models.CharField(max_length=100, blank=True, help_text='base_url地址', verbose_name='base_url地址', )
headers = models.JSONField(default=dict, null=True, blank=True, help_text='请求头', verbose_name='请求头')
global_func = models.TextField(default="", null=True, blank=True, help_text='全局工具函数文件', verbose_name='全局工具函数文件')
def __str__(self):
return self.name
class Meta:
db_table = 'test_env'
verbose_name_plural = "测试环境表"
③数据迁移:略
④注册admin
@admin.register(TestEnv)
class TestEnvAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'host', 'headers']
2-2接口说明
# 获取测试环境列表、获取测试环境详情、增加测试环境、删除测试环境、编辑测试环境
2-3序列化器
class TestEnvSerializer(serializers.ModelSerializer):
"""测试环境序列化器"""
class Meta:
model = TestEnv
fields = '__all__'
2-4视图集
①配置参数过滤器
# 配置 rest_framework
REST_FRAMEWORK = {
# 配置登录鉴权方式
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
# 配置drf使用的视图过滤器
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
}
②创建视图集
class TestEnvViewSet(ModelViewSet):
"""测试环境视图集"""
queryset = TestEnv.objects.all()
serializer_class = TestEnvSerializer
# 鉴权
permission_classes = [IsAuthenticated]
# 参数过滤
filterset_fields = ['project']
2-5注册路由
router.register(r'api/testPro/envs', TestEnvViewSet) # 测试环境
2-6接口调试
3-1测试文件模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
file | file | 否 | 文件 | |
info | json | 是 | [] | 文件保存的数据信息 |
②模型类创建
class TestFile(models.Model):
"""文件上传"""
file = models.FileField(help_text='文件', verbose_name='文件')
info = models.JSONField(default=list, null=True, blank=True, help_text='数据', verbose_name='数据', )
def __str__(self):
return self.info
class Meta:
db_table = 'test_file'
verbose_name_plural = "测试文件表"
③数据迁移:略
④注册admin:略
3-2接口说明
# 获取测试文件列表、上传测试文件、删除测试文件
3-3序列化器
class TestFileSerializer(serializers.ModelSerializer):
"""测试文件序列化器"""
class Meta:
model = TestFile
fields = '__all__'
3-4视图集
class TestFileViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
"""测试文件视图集"""
queryset = TestFile.objects.all().order_by('-id')
serializer_class = TestFileSerializer
permission_classes = [IsAuthenticated]
def create(self, request, *args, **kwargs):
"""文件上传的方法"""
# 获取上传的文件大小和文件名
size = request.data['file'].size
name = request.data['file'].name
if size > 1024 * 300:
return Response({"error": "文件大小不能超过300KB"}, status=status.HTTP_400_BAD_REQUEST)
if os.path.isfile(settings.MEDIA_ROOT / name):
return Response({"error": "文件不能重复上传"}, status=status.HTTP_400_BAD_REQUEST)
file_type = request.data['file'].content_type
file_path = f"files/{name}"
request.data["info"] = json.dumps([name, file_path, file_type])
return super().create(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
"""文件删除的方法"""
# 获取文件路径
info = self.get_object().info
file_path = info[1] if len(info) > 1 else None
result = super().destroy(request, *args, **kwargs)
if file_path:
os.remove(file_path)
return result
3-5注册路由
3-6接口调试
六、项目接口管理模块开发
1-1测试接口模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 关联项目 | |
name | varchar | 否 | 接口名称 | |
url | varchar | 否 | 接口地址 | |
method | varchar | 否 | 请求方法 | |
type | varchar | 否 | 1 | 接口类型(项目接口、第三方接口) |
②模型类创建
class TestInterface(models.Model):
"""测试接口表"""
CHOICES = [
('1', '项目接口'),
('2', '外部接口')
]
project = models.ForeignKey(TestProject, on_delete=models.CASCADE, help_text='项目id', verbose_name='项目id')
name = models.CharField(max_length=50, help_text='接口名称', verbose_name='接口名')
url = models.CharField(max_length=200, help_text='接口路径', verbose_name='接口路径')
method = models.CharField(max_length=50, help_text='请求方法', verbose_name='请求方法')
type = models.CharField(max_length=40, choices=CHOICES, default='1', verbose_name='接口类型', help_text='接口类型')
def __str__(self):
return self.url
class Meta:
db_table = 'test_interface'
verbose_name_plural = "测试接口表"
③数据库迁移
④注册admin
1-2接口说明
# 获取接口列表、增加接口、删除接口、修改接口
1-3序列化器
class TestInterfaceSerializer(serializers.ModelSerializer):
"""接口序列化器"""
class Meta:
model = TestInterface
fields = '__all__'
1-4视图集
class TestInterfaceViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
"""接口视图集"""
queryset = TestInterface.objects.all()
serializer_class = TestInterfaceSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['project']
def get_serializer_class(self):
if self.action == 'list':
return TestInterfaceListSerializer
else:
return self.serializer_class
1-5注册路由
1-6接口调试
2-1接口用例模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
title | varchar | 否 | 用例名称 | |
interface | ForeignKey | 否 | 所属接口 | |
headers | json | 是 | {} | 请求头配置 |
request | json | 是 | {} | 请求参数 |
file | json | 是 | [] | 请求上传文件的参数 |
setup_script | TextField | 是 | 前置脚本 | |
teardown_script | TextField | 是 | 后置断言脚本 |
②模型类创建
class TestInterfaceCase(models.Model):
"""测试接口用例表"""
interface = models.ForeignKey(TestInterface, on_delete=models.CASCADE, verbose_name='接口', help_text='接口')
title = models.CharField(verbose_name='用例名称', help_text='用例名称', max_length=50)
headers = models.JSONField(verbose_name='请求头配置', help_text='请求头', null=True, default=dict, blank=True)
request = models.JSONField(verbose_name='请求参数配置', help_text='请求参数配置', null=True, default=dict, blank=True)
file = models.JSONField(verbose_name='请求上传的文件参数', help_text='请求上传的文件参数', null=True, default=list, blank=True)
setup_script = models.TextField(verbose_name='前置脚本', help_text='前置脚本', null=True, blank=True, default='')
teardown_script = models.TextField(verbose_name='后置脚本', help_text='后置脚本', null=True, blank=True, default='')
def __str__(self):
return self.title
class Meta:
db_table = 'test_interface_case'
verbose_name_plural = "测试接口用例表"
③数据迁移
④注册admin
2-2接口说明
# 获取接口用例列表、详情、增加、删除、修改、运行单条接口用例
2-3序列化器
from rest_framework import serializers
from TestInterface.models import TestInterface, TestInterfaceCase
class TestInterfaceSerializer(serializers.ModelSerializer):
"""接口序列化器"""
class Meta:
model = TestInterface
fields = '__all__'
class TestInterfaceCaseSerializer(serializers.ModelSerializer):
"""接口用例序列化器"""
class Meta:
model = TestInterfaceCase
fields = '__all__'
class TestInterfaceCaseListSerializer(serializers.ModelSerializer):
"""接口用例-列表 序列化器"""
class Meta:
model = TestInterfaceCase
fields = ['id', 'title']
class TestInterfaceCaseGetSerializer(serializers.ModelSerializer):
"""接口用例-详情 序列化器"""
interface = TestInterfaceSerializer()
class Meta:
model = TestInterfaceCase
fields = '__all__'
class TestInterfaceListSerializer(serializers.ModelSerializer):
"""接口-列表 序列化器"""
cases = TestInterfaceCaseListSerializer(read_only=True, many=True, source='testinterfacecase_set')
class Meta:
model = TestInterface
fields = '__all__'
2-4视图集
class TestInterfaceCaseViewSet(ModelViewSet):
"""接口用例视图集"""
queryset = TestInterfaceCase.objects.all()
serializer_class = TestInterfaceCaseSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['interface']
def get_serializer_class(self):
if self.action == 'list':
return TestInterfaceCaseListSerializer
elif self.action == 'retrieve':
return TestInterfaceCaseGetSerializer
else:
return self.serializer_class
def run_cases(self, request):
"""
:param request:
env:测试环境
cases_data:测试数据
:return:
"""
env_id = request.data.get('env')
case_data = request.data.get('cases')
if not all([env_id, case_data]):
return Response({'error': "参数env和cases均不能为空"})
env = TestEnv.objects.get(id=env_id)
# 获取用例运行的相关配置
config = {
"ENV": {
'host': env.host,
'headers': env.headers,
**env.global_variable,
**env.debug_global_variable
},
"DB": env.db,
"global_func": env.global_func,
}
# 将运行的环境变量保存到测试环境的 debug_global_variable 中
res, env_var = run_test(case_data=[{"Cases": [case_data]}], env_config=config, debug=True)
# 获取用例执行的结果
result = res['results'][0]['cases'][0]
# 保存debug模式的环境变量
env.debug_global_variable = env_var
env.save()
return Response(result)
2-5 注册路由
2-6 接口调试
七、测试场景模块开发
1-1测试场景模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 关联项目 | |
name | varchar | 否 | 业务流名称 |
②模型类创建
class TestScene(models.Model):
"""测试业务流"""
project = models.ForeignKey(TestProject, on_delete=models.PROTECT, help_text='项目id', verbose_name='项目id')
name = models.CharField(max_length=50, help_text='测试业务流名', verbose_name='测试业务流名')
def __str__(self):
return self.name
class Meta:
db_table = 'test_scene'
verbose_name_plural = "测试业务流表"
③数据迁移
④注册admin
1-2接口说明
# 获取场景步骤列表、增加、删除、修改、运行测试场景
1-3-序列化器
class TestSceneSerializer(serializers.ModelSerializer):
"""测试业务流序列化器"""
class Meta:
model = TestScene
fields = '__all__'
1-4视图集
class TestSceneViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
queryset = TestScene.objects.all()
serializer_class = TestSceneSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['project']
def run_scene(self, request):
"""运行测试业务流"""
# 获取参数:env 和scene,校验参数是否为空
env_id = request.data.get('env')
scene_id = request.data.get('scene')
if not all([env_id, scene_id]):
return Response({'error': "参数env和scene均不能为空"}, status=400)
# 获取测试环境数据
env = TestEnv.objects.get(id=env_id)
env_config = {
"ENV": {
"host": env.host,
"headers": env.headers,
**env.global_variable,
},
"DB": env.db,
"global_func": env.global_func
}
# 获取测试业务流中的用例数据
scene = TestScene.objects.get(id=scene_id)
scene_cases = scene.testscenecase_set.all()
res = TestSceneCaseReadSerializer(scene_cases, many=True).data
# 根据sort字段进行排序
datas = sorted(res, key=lambda x: x['sort'])
cases = [i['icase'] for i in datas]
# 执行的用例数据
case_data = [
{
"name": scene.name,
"Cases": cases
}
]
# 调用执行引擎的run_test方法运行测试
result = run_test(case_data=case_data, env_config=env_config, debug=False)
return Response(result['results'][0], status=200)
1-5注册路由
1-6接口调试
2-1测试场景用例模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
icase | ForeignKey | 否 | 接口用例 | |
scene | ForeignKey | 否 | 业务流 | |
sort | int | 是 | 业务流中的用例执行顺序 |
②模型类创建
class TestSceneCase(models.Model):
"""测试业务流用例"""
scene = models.ForeignKey(TestScene, on_delete=models.PROTECT, verbose_name='测试业务流id', help_text='测试业务流id')
icase = models.ForeignKey(TestInterfaceCase, on_delete=models.PROTECT, verbose_name='接口用例id', help_text='接口用例id')
sort = models.IntegerField(verbose_name='执行顺序', help_text='执行顺序', null=True, blank=True)
def __str__(self):
return self.icase.title
class Meta:
db_table = 'test_scene_case'
verbose_name_plural = "测试业务流执行步骤表"
③数据迁移
④注册admin
2-2接口说明
# 获取场景用例列表,增加、删除、修改场景用例
2-3序列化器
class TestSceneCaseSerializer(serializers.ModelSerializer):
"""测试业务流-执行步骤 序列化器"""
class Meta:
model = TestSceneCase
fields = '__all__'
class TestSceneCaseListSerializer(serializers.ModelSerializer):
"""测试业务流-执行步骤-列表 序列化器"""
icase = TestInterfaceCaseListSerializer()
class Meta:
model = TestSceneCase
fields = '__all__'
# 读取测试业务流中 用例数据的序列化器
class TestSceneCaseReadSerializer(serializers.ModelSerializer):
"""测试业务流-执行步骤-用例数据 序列化器"""
icase = TestInterfaceCaseGetSerializer()
class Meta:
model = TestSceneCase
fields = '__all__'
2-4视图集
class TestSceneCaseViewSet(mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
queryset = TestSceneCase.objects.all()
serializer_class = TestSceneCaseSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['scene']
def get_serializer_class(self):
if self.action == 'list':
return TestSceneCaseListSerializer
else:
return self.serializer_class
class TestSceneCaseUpdateView(APIView):
"""修改测试场景中的执行顺序"""
def patch(self, request, *args, **kwargs):
datas = request.data
for item in datas:
obj = TestSceneCase.objects.get(id=item['id'])
obj.sort = item['sort']
obj.save()
return Response({"msg": "修改成功", "data": datas}, status=status.HTTP_200_OK)
2-5注册路由
2-6接口调试
八、测试任务模块开发
1-1测试任务模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 所属项目 | |
name | String | 否 | 任务名称 | |
scene | ManyToManyField | 是 | 包含的测试业务 |
②模型类创建
class TestTask(models.Model):
"""测试任务的模型类"""
project = models.ForeignKey(TestProject, on_delete=models.PROTECT, verbose_name="所属项目id", help_text='所属项目id')
name = models.CharField(max_length=50, help_text='任务名称', verbose_name='任务名称')
scene = models.ManyToManyField(TestScene, blank=True, help_text='业务流id', verbose_name='业务流id')
def __str__(self):
return self.name
class Meta:
db_table = 'test_task'
verbose_name_plural = '测试任务表'
③数据迁移
④注册admin
1-2接口说明
# 获取测试任务列表、详情,增加、删除、修改、运行测试任务
1-3序列化器
class TestTaskSerializer(serializers.ModelSerializer):
"""测试任务 的序列化器"""
class Meta:
model = TestTask
fields = '__all__'
class TestTaskGetSerializer(serializers.ModelSerializer):
scene = TestSceneSerializer(many=True)
"""测试任务-详情 的序列化器"""
class Meta:
model = TestTask
fields = '__all__'
class TestRecordSerializer(serializers.ModelSerializer):
"""测试记录 序列化器"""
env = serializers.StringRelatedField(read_only=True, source='env.name')
task = serializers.StringRelatedField(read_only=True, source='task.name')
class Meta:
model = TestRecord
fields = '__all__'
1-4视图集
class TestTaskViewSet(ModelViewSet):
queryset = TestTask.objects.all()
serializer_class = TestTaskSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['project']
def get_serializer_class(self):
if self.action == 'retrieve':
return TestTaskGetSerializer
else:
return self.serializer_class
def run_task(self, request):
# 1、获取参数并进行校验
env_id = request.data.get('env')
task_id = request.data.get('task')
if not all([env_id, task_id]):
return Response({"error": "参数env和task均不能为空"}, status=status.HTTP_400_BAD_REQUEST)
# 使用celery异步执行测试任务
run_task(env_id, task_id, request.user.username)
return Response({"msg": "测试任务已经开始执行"}, status=status.HTTP_200_OK)
1-5注册路由
1-6接口调试
2-1测试记录/测试报告模型类
①数据库设计:测试记录、测试报告
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
task | ForeignKey | 否 | 执行的测试任务 | |
all | int | 是 | 0 | 用例总数 |
success | int | 是 | 0 | 成功用例数 |
fail | int | 是 | 0 | 失败用例数 |
error | int | 是 | 0 | 错误用例数 |
pass_rate | varchar | 是 | ‘0’ | 通过率 |
tester | varchar | 是 | 执行者 | |
env | ForeignKey | 否 | 测试环境 | |
statue | varchar | 否 | 执行状态 | |
create_time | DataTime | 否 | 执行时间 |
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
info | JSONField | 是 | 报告数据 | |
record | OneToOneField | 是 | 测试记录 |
②模型类创建
class TestRecord(models.Model):
"""测试运行记录"""
task = models.ForeignKey(TestTask, on_delete=models.CASCADE, verbose_name='测试任务表', help_text='测试任务表')
env = models.ForeignKey(TestEnv, on_delete=models.PROTECT, verbose_name='执行环境', help_text='执行环境')
all = models.IntegerField(verbose_name='用例总数', help_text='用例总数', default=0, blank=True)
success = models.IntegerField(verbose_name='通过用例数', help_text='通过用例数', default=0, blank=True)
fail = models.IntegerField(verbose_name='失败用例数', help_text='失败用例数', default=0, blank=True)
error = models.IntegerField(verbose_name='错误用例数', help_text='错误用例数', default=0, blank=True)
pass_rate = models.CharField(max_length=50, verbose_name='用通过率', help_text='用通过率', default='0', blank=True)
tester = models.CharField(max_length=50, verbose_name='执行者', help_text='执行者', blank=True)
status = models.CharField(max_length=50, verbose_name='执行状态', help_text='执行状态')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间')
def __str__(self):
return str(self.id)
class Meta:
db_table = 'test_record'
verbose_name_plural = '测试任务运行记录表'
class TestReport(models.Model):
"""测试报告"""
record = models.ForeignKey(TestRecord, on_delete=models.CASCADE, verbose_name='测试记录id', help_text='测试记录id')
info = models.JSONField(verbose_name='报告的数据', help_text='报告的数据', default=dict, blank=True)
def __str__(self):
return str(self.id)
class Meta:
db_table = 'test_report'
verbose_name_plural = '测试报告表'
③数据库迁移
④注册admin
2-2接口说明
# 测试记录:获取测试记录列表(带参数)
# 测试报告:获取测试报告详情
2-3序列化器
class TestRecordSerializer(serializers.ModelSerializer):
"""测试记录 序列化器"""
env = serializers.StringRelatedField(read_only=True, source='env.name')
task = serializers.StringRelatedField(read_only=True, source='task.name')
class Meta:
model = TestRecord
fields = '__all__'
class TestReportSerializer(serializers.ModelSerializer):
"""测试报告 序列化器"""
class Meta:
model = TestReport
fields = '__all__'
2-4 视图集
class TestRecordFilterSet(FilterSet):
"""测试记录的过滤器"""
project = filters.NumberFilter(field_name='task__project')
class Meta:
model = TestRecord
# 指定过滤的参数
fields = ['task', 'project']
class TestRecordViewSet(mixins.ListModelMixin, GenericViewSet):
"""测试记录视图集"""
queryset = TestRecord.objects.all().order_by('-create_time')
serializer_class = TestRecordSerializer
permission_classes = [IsAuthenticated]
filterset_class = TestRecordFilterSet
class TestReportViewSet(mixins.RetrieveModelMixin, GenericViewSet):
"""测试报告视图集"""
queryset = TestReport.objects.all()
serializer_class = TestReportSerializer
permission_classes = [IsAuthenticated]
# 这里更换为使用记录ID,查询对应的报告,进行返回
def retrieve(self, request, *args, **kwargs):
record = TestRecord.objects.get(id=kwargs['pk'])
report = TestReport.objects.get(record=record)
serializer = self.serializer_class(report)
return Response(serializer.data)
2-5注册路由
2-6接口调试
九、定时任务模块开发
0-celery环境
①celery环境配置
# 1-安装
pip install django_celery_beat
# 2-注册
INSTALLED_APPS = [
...
'django_celery_beat'
]
# 3-数据迁移: 略
# 4-配置
# =========celery的配置====================
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
# 配置任务消息中间件
CELERY_BROKER_URL = 'redis://localhost:6379/3'
# 指定调度器模型类
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
# 5-创建celery任务:项目`setting.py`同级的目录创建下`celery.py`
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'apiTestPlatform.settings')
celery_app = Celery('cly')
# 加载settings中的配置
celery_app.config_from_object('django.conf:settings', namespace='CELERY')
# 自动加载Django应用下tasks.py中注册的celery任务函数
celery_app.autodiscover_tasks()
# 6-测试任务模块下创建tasks.py
@celery_app.task
def run_task(env_id, task_id, tester):
# 2、获取测试环境数据
env = TestEnv.objects.get(id=env_id)
env_config = {
"ENV": {
"host": env.host,
"headers": env.headers,
**env.global_variable,
},
"DB": env.db,
"global_func": env.global_func
}
# 3、获取用例数据
task = TestTask.objects.get(id=task_id)
scenes = task.scene.all()
case_data = []
for scene in scenes:
scene_cases = scene.testscenecase_set.all()
res = TestSceneCaseReadSerializer(scene_cases, many=True).data
datas = sorted(res, key=lambda x: x['sort'])
cases = [i['icase'] for i in datas]
case_data.append({
"name": scene.name,
"Cases": cases
})
# 4、创建一条运行记录
record = TestRecord.objects.create(task=task, env=env, tester=tester, status='执行中')
# 5、运行测试
result = run_test(case_data=case_data, env_config=env_config, debug=False)
# 6、创建测试报告 更新测试记录
TestReport.objects.create(info=result, record=record)
record.all = result['all']
record.success = result['success']
record.fail = result['fail']
record.error = result['error']
record.pass_rate = '{:2f}'.format(result['success'] / result['all'])
record.statue = '执行完毕'
record.save()
# 7、返回执行结果
return result
1-定时任务模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 所属项目 | |
create_time | DataTime | 否 | 创建时间 | |
name | varchar | 否 | 定时任务名称 | |
rule | varchar | 否 | * * * * * | 定时执行规则 |
status | Boolean | 否 | flase | 是否启用 |
env | ForeignKey | 否 | 执行使用测试环境 | |
task | ForeignKey | 否 | 执行的测试任务 |
②模型类创建
class TestCronjob(models.Model):
"""定时任务表"""
project = models.ForeignKey(TestProject, on_delete=models.CASCADE, help_text='项目id', verbose_name='项目id')
env = models.ForeignKey(TestEnv, help_text='执行环境', verbose_name='执行环境', on_delete=models.PROTECT)
task = models.ForeignKey(TestTask, help_text='执行任务', verbose_name='执行任务', on_delete=models.PROTECT)
name = models.CharField(max_length=150, help_text='名称', verbose_name='名称')
rule = models.CharField(help_text='定时执行规则', verbose_name='定时执行规则', max_length=80, default='* * * * *')
status = models.BooleanField(help_text='状态', verbose_name='状态', default=False)
create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
def __str__(self):
return self.name
class Meta:
db_table = 'test_cronjob'
verbose_name_plural = "定时任务表"
③数据迁移
④注册admin
2-接口说明
# 获取定时任务列表,增加、删除、修改定时任务
3-序列化器
class TestCronjobSerializer(serializers.ModelSerializer):
"""定时任务 序列化器"""
env_name = serializers.StringRelatedField(read_only=True, source='env.name')
task_name = serializers.StringRelatedField(read_only=True, source='task.name')
class Meta:
model = TestCronjob
fields = '__all__'
4-视图集
class TestCronjobViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
"""定时任务视图"""
queryset = TestCronjob.objects.all()
serializer_class = TestCronjobSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['project', 'task']
def create(self, request, *args, **kwargs):
"""创建定时任务"""
with transaction.atomic():
save_point = transaction.savepoint()
try:
# 1、调用父类方法创建定时任务(在 CronJob 表中添加一条数据)
result = super().create(request, *args, **kwargs)
# 2、获取创建定时任务的规则
rule_list = result.data.get('rule').split(' ')
cron_dict = dict(zip(['minute', 'hour', 'day_of_week', 'day_of_month', 'month_of_year'], rule_list))
# 3、创建一个规则对象(在 django-celery-beat 这个应用的 CrontabSchedule 表添加一条数据)
try:
cron = CrontabSchedule.objects.get(**cron_dict)
except:
cron = CrontabSchedule.objects.create(**cron_dict)
# 4、创建一个周期任务(在 django-celery-beat 这个应用的 PeriodicTask 表添加一条数据)
PeriodicTask.objects.create(name=result.data.get('id'), # 这里name的值为创建的定时任务CronJob对象id,方便进行修改,类似关联了CronJob的主键
task='TestTask.tasks.run_task',
crontab=cron,
kwargs=json.dumps({
"env_id": result.data.get('env'),
"task_id": result.data.get('task'),
"tester": request.user.username
}),
enabled=result.data.get('status'))
except:
# 回滚
transaction.savepoint_rollback(save_point)
return Response({"error": "定时任务创建失败"}, status=500)
else:
# 提交
transaction.savepoint_commit(save_point)
return result
def destroy(self, request, *args, **kwargs):
"""删除定时任务"""
with transaction.atomic():
save_point = transaction.savepoint()
try:
# 1、删除周期任务对象 PeriodicTask
cronjob = self.get_object()
p_task = PeriodicTask.objects.get(name=cronjob.id)
p_task.enabled = False
p_task.delete()
# 2、删除定时任务表 TestCronjob
result = super().destroy(request, *args, **kwargs)
except:
transaction.savepoint_rollback(save_point)
return Response({"error": "定时任务删除失败"}, status=500)
else:
transaction.savepoint_commit(save_point)
return result
def update(self, request, *args, **kwargs):
"""修改定时任务"""
with transaction.atomic():
save_point = transaction.savepoint()
try:
# 1、调用父类方法更新定时任务(在 CronJob 表中更新一条数据)
result = super().update(request, *args, **kwargs)
# 2、获取定时任务对象
cronjob = self.get_object()
# 3、更新周期任务
# 3.1、获取周期任务对象
p_task = PeriodicTask.objects.get(name=cronjob.id)
p_task.kwargs = json.dumps({
"env_id": result.data.get('env'),
"task_id": result.data.get('task')
})
p_task.enabled = result.data.get('status')
# 3.2、获取定期执行规则
rule_list = result.data.get('rule').split(' ')
cron_dict = dict(zip(['minute', 'hour', 'day_of_week', 'day_of_month', 'month_of_year'], rule_list))
try:
cron = CrontabSchedule.objects.get(**cron_dict)
except:
cron = CrontabSchedule.objects.create(**cron_dict)
# 3.3、修改定期执行规则
p_task.crontab = cron
p_task.save()
except:
transaction.savepoint_rollback(save_point)
return Response({"error": "定时任务修改失败"}, status=500)
else:
transaction.savepoint_commit(save_point)
return result
5-注册路由
6-接口调试
十、BUG管理模块开发
1-测试BUG/BUG处理记录模型类
①数据库设计
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
project | ForeignKey | 否 | 所属项目 | |
create_time | DataTime | 否 | 创建时间 | |
name | varchar | 否 | 定时任务名称 | |
rule | varchar | 否 | * * * * * | 定时执行规则 |
status | Boolean | 否 | flase | 是否启用 |
env | ForeignKey | 否 | 执行使用测试环境 | |
task | ForeignKey | 否 | 执行的测试任务 |
字段 | 类型 | 空 | 默认 | 注释 |
---|---|---|---|---|
id | int | 否 | 自增长主键ID | |
bug | ForeignKey | 否 | bug | |
create_time | datatime | 否 | 提交时间 | |
handle | TextField | 是 | 处理操作 | |
update_user | varchar | 是 | 处理用户 |
②模型类创建
class TestBug(models.Model):
"""bug管理的模型类"""
interface = models.ForeignKey(TestInterface, on_delete=models.CASCADE, verbose_name="所属接口", help_text="所属接口")
desc = models.CharField(max_length=30, verbose_name="bug描述", help_text="bug描述", blank=True, null=True)
# bug状态:新增、处理中、挂起、已关闭、已修复、重新打开
status = models.CharField(max_length=10, help_text="bug状态", verbose_name="bug状态", default='新增')
user = models.CharField(max_length=10, help_text="提交者", verbose_name="提交者", blank=True, null=True)
info = models.JSONField(help_text="用例执行信息", verbose_name='用例执行信息', default=dict, blank=True, null=True)
create_time = models.DateTimeField(auto_now_add=True, help_text="提交时间", verbose_name="提交时间")
def __str__(self):
return str(self.id)
class Meta:
db_table = 'test_bug'
verbose_name_plural = 'bug管理表'
class TestBugHandle(models.Model):
"""bug处理记录表"""
bug = models.ForeignKey('TestBug', on_delete=models.CASCADE, help_text='bug ID', verbose_name='bug ID')
handle = models.TextField(help_text='处理操作', verbose_name='处理操作', blank=True)
update_user = models.CharField(max_length=32, verbose_name='更新用户', help_text='更新用户', blank=True)
create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
class Meta:
db_table = 'test_bug_handle'
verbose_name_plural = "bug操作记录表"
③注册路由
④注册admin
2- 接口说明
# 获取BUG列表、详情,创建、修改BUG
3-序列化器
class TestBugHandleSerializer(serializers.ModelSerializer):
"""bug处理记录 的序列化器"""
class Meta:
model = TestBugHandle
fields = '__all__'
class TestBugSerializer(serializers.ModelSerializer):
"""bug 的序列化器"""
interface_url = serializers.StringRelatedField(source='interface.url', read_only=True)
handle = TestBugHandleSerializer(many=True, source="testbughandle_set", read_only=True)
class Meta:
model = TestBug
fields = '__all__'
class TestBugListSerializer(serializers.ModelSerializer):
"""bug-列表 的序列化器"""
interface_url = serializers.StringRelatedField(source='interface.url', read_only=True)
class Meta:
model = TestBug
fields = ['id', 'create_time', 'desc', 'status', 'user', 'interface', 'interface_url']
4-视图集
class TestBugViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, GenericViewSet):
queryset = TestBug.objects.all()
serializer_class = TestBugSerializer
permission_classes = [IsAuthenticated]
def get_serializer_class(self):
if self.action == 'list':
return TestBugListSerializer
else:
return self.serializer_class
def create(self, request, *args, **kwargs):
# 1、创建一条BUG
result = super().create(request, *args, **kwargs)
bug = TestBug.objects.get(id=result.data.get('id'))
handle_info = "提交BUG,BUG的状态是:{}".format(result.data.get('status'))
# 2、创建一条BUG处理记录
TestBugHandle.objects.create(bug=bug, handle=handle_info, update_user=request.user.username)
return result
def update(self, request, *args, **kwargs):
# 1、修改一条BUG
result = super().update(request, *args, **kwargs)
bug = self.get_object()
# 2、新增一条BUG处理记录
handle_info = "修改BUG,BUG的状态是:{}".format(result.data.get('status'))
TestBugHandle.objects.create(bug=bug, handle=handle_info, update_user=request.user.username)
return result
5-注册路由
6-接口调试
十一、后端部署配置
1-Ajax跨域配置
针对于前后端分离的项目,前端和后台是分开部署的,因此服务端要支持CORS(跨域源资源共享)
策略,需要在响应头中加上Access-Control-Allow-Origin: *`
# 后端服务:127.0.0.1:8000
# 前端服务:127.0.0.1:8080
# 添加跨域请求配置
# 1-安装处理跨域资源共享第三方库
pip install django-cors-headers
# 2-注册应用
INSTALLED_APPS = (
...
# 实现对前端跨域请求的支持
'corsheaders',
...
)
# 3-设置中间件
MIDDLEWARE = [
# 实现对跨域请求的支持:加上corsheaders的中间件
'corsheaders.middleware.CorsMiddleware',
...
]
# 4-添加访问后端服务白名单
# 第一种:凡是出现在白名单中的域名,都可以访问后端接口
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:8848',
'http://localhost:8080',
)
# 第二种:直接允许所有
# 允许所有用户跨域访问(使CORS_ORIGIN_WHITELIST失效)
CORS_ORIGIN_ALLOW_ALL = True
# CORS_ALLOW_CREDENTIALS 指明在跨域访问中,后端是否支持对cookie的操作。
CORS_ALLOW_CREDENTIALS = True
2-依赖库导出
pip freeze > requirements.txt
# 导出后,删除本地依赖文件的示例:
amqp==5.2.0
ApiTestEngine==1.0.3
asgiref==3.8.1
async-timeout==4.0.3
billiard==4.2.0
celery==5.4.0
certifi==2024.6.2
charset-normalizer==2.0.12
click==8.1.7
click-didyoumean==0.3.1
click-plugins==1.1.1
click-repl==0.3.0
colorama==0.4.6
cron-descriptor==1.4.3
Django==4.2
django-celery-beat==2.6.0
django-cors-headers==4.3.1
django-filter==24.2
django-timezone-field==6.1.0
djangorestframework==3.14.0
djangorestframework-simplejwt==5.3.1
Faker==13.4.0
idna==3.7
jsonpath==0.82
kombu==5.3.7
mysqlclient==2.2.4
prompt_toolkit==3.0.46
pyasn1==0.6.0
PyJWT==2.8.0
PyMySQL==1.0.2
python-crontab==3.1.0
python-dateutil==2.9.0.post0
pytz==2024.1
redis==5.0.5
requests==2.27.1
requests-toolbelt==0.9.1
rsa==4.8
six==1.16.0
typing_extensions==4.12.2
urllib3==1.26.18
vine==5.1.0
wcwidth==0.2.13
十二、说明
后端开发完成后,可以部署在本地或者云服务器。
如果公司有内网的情况下,建议部署在本地:使用django的waitress库(一个python的WSGI服务器)+NSSM(windows服务管理工具)
示例:作为windows服务运行,不需要再启用pycharm运行
如果部署在云服务器,建议使用宝塔面板,大致过程:
# 1-环境安装
安装MySQL
安装redis
安装nginx
安装python
# 2-更改代码配置
修改MySQL数据库配置
关闭调试模式
允许所有IP访问
修改redis数据库配置
更改静态文件设置
收集静态文件到指定路径
# 3-创建项目
上传后端代码
创建django项目
安装项目依赖库
# 4-数据迁移
数据迁移
创建超级管理员
重启项目
示例:
postman调试: