Bootstrap

【接口自动化测试平台】后端开发笔记

接口测试平台后端开发笔记(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

请求参数:

参数名必选类型说明
refreshstringrefresh_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

请求参数:

参数名必选类型说明
tokenstringrefresh_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测试项目模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
namevarchar项目名称
leadervarchar项目负责人
create_timetimestamp添加时间

②模型类创建

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测试环境模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey关联项目
global_variablejson{}全局变量
debug_global_variablejson{}调试模式全局变量
dbjson{}数据库配置(这里列表?)
hostvarchar测试环境host地址
headersjson{}全局请求头配置
global_functextField全局工具函数文件
namevarchar测试环境名称

②模型类创建

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测试文件模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
filefile文件
infojson[]文件保存的数据信息

②模型类创建

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测试接口模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey关联项目
namevarchar接口名称
urlvarchar接口地址
methodvarchar请求方法
typevarchar1接口类型(项目接口、第三方接口)

②模型类创建

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接口用例模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
titlevarchar用例名称
interfaceForeignKey所属接口
headersjson{}请求头配置
requestjson{}请求参数
filejson[]请求上传文件的参数
setup_scriptTextField前置脚本
teardown_scriptTextField后置断言脚本

②模型类创建

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测试场景模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey关联项目
namevarchar业务流名称

②模型类创建

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测试场景用例模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
icaseForeignKey接口用例
sceneForeignKey业务流
sortint业务流中的用例执行顺序

②模型类创建

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测试任务模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey所属项目
nameString任务名称
sceneManyToManyField包含的测试业务

②模型类创建

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测试记录/测试报告模型类

①数据库设计:测试记录、测试报告

字段类型默认注释
idint自增长主键ID
taskForeignKey执行的测试任务
allint0用例总数
successint0成功用例数
failint0失败用例数
errorint0错误用例数
pass_ratevarchar‘0’通过率
testervarchar执行者
envForeignKey测试环境
statuevarchar执行状态
create_timeDataTime执行时间
字段类型默认注释
idint自增长主键ID
infoJSONField报告数据
recordOneToOneField测试记录

②模型类创建

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-定时任务模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey所属项目
create_timeDataTime创建时间
namevarchar定时任务名称
rulevarchar* * * * *定时执行规则
statusBooleanflase是否启用
envForeignKey执行使用测试环境
taskForeignKey执行的测试任务

②模型类创建

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处理记录模型类

①数据库设计

字段类型默认注释
idint自增长主键ID
projectForeignKey所属项目
create_timeDataTime创建时间
namevarchar定时任务名称
rulevarchar* * * * *定时执行规则
statusBooleanflase是否启用
envForeignKey执行使用测试环境
taskForeignKey执行的测试任务
字段类型默认注释
idint自增长主键ID
bugForeignKeybug
create_timedatatime提交时间
handleTextField处理操作
update_uservarchar处理用户

②模型类创建

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调试:

在这里插入图片描述

;