这里写目录标题
- 一、项目应用
- 1、项目包含接口:
- 2、创建子应用
- 3、项目模块设计
- a、模型类设计
- b、序列化器类设计
- c、视图类设计
- 4、接口模块设计
- a、模型类设计
- b、序列化器类设计
- c、视图类设计
- 5、环境模块设计
- 6、DRF中的通用过滤
- 6.1、设置过滤器后端
一、项目应用
1、项目包含接口:
- 项目管理接口
- 接口管理接口
- 环境管理接口
2、创建子应用
python manage.py startapp projects
3、项目模块设计
a、模型类设计
from django.db import models
# Create your models here.
class Project(models.Model):
"""项目表"""
name = models.CharField(max_length=50, help_text='项目名称', verbose_name='项目名')
leader = models.CharField(max_length=50, help_text='负责人', verbose_name='负责人', default='')
create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
class Meta:
db_table = 'tb_project'
verbose_name = '项目表'
verbose_name_plural = verbose_name
def _str__(self):
return self.name
b、序列化器类设计
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
class ProjectSerializer(ModelSerializer):
class Meta:
model = Project
fields = ['id', 'name', 'leader', 'create_time']
c、视图类设计
class ProjectViewSet(ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
获取项目的详情数据
需要展示字段:执行环境、执行场景、测试计划、接口数量、定时任务、执行记录
方法一:需要重写retrieve方法
class ProjectViewSet(ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
# permission_classes = [IsAuthenticated]
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(self, request, *args, **kwargs)
obj = self.get_object()
response.data['info'] = [
{'name': '执行环境', 'value': TestEnv.objects.filter(project_id=obj.id).count()},
{'name': '执行场景', 'value': TestScene.objects.filter(project_id=obj.id).count()},
{'name': '测试计划', 'value': TestPlan.objects.filter(project_id=obj.id).count()},
{'name': '接口数量', 'value': Interface.objects.filter(project_id=obj.id).count()},
{'name': '定时任务', 'value': 0}, # todo 定时任务未开发
{'name': '执行记录', 'value': Record.objects.filter(plan__project=obj).count()}
]
return response
方法二:模型类中定义新的字段(重点)
模型类
class Project(models.Model):
"""项目表"""
name = models.CharField(max_length=50, unique=True, help_text='项目名称', verbose_name='项目名')
leader = models.CharField(max_length=50, help_text='负责人', verbose_name='负责人', default='')
create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
class Meta:
db_table = 'tb_project'
verbose_name = '项目表'
verbose_name_plural = verbose_name
def _str__(self):
return self.name
def info(self):
return [
{'name': '执行环境', 'value': self.test_envs.count()},
{'name': '执行场景', 'value': self.test_scenes.count()},
{'name': '测试计划', 'value': self.test_plans.count()},
{'name': '接口数量', 'value': self.interfaces.count()},
{'name': '定时任务', 'value': 0}, #todo 定时任务未开发
{'name': '执行记录', 'value': Record.objects.filter(plan__project=self).count()}
]
序列化器设计
class ProjectSerializer(ModelSerializer):
class Meta:
model = Project
fields = ['id', 'name', 'leader', 'create_time', 'info', 'bugs']
视图设计
class ProjectViewSet(ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
4、接口模块设计
a、模型类设计
class Interface(models.Model):
"""接口表"""
CHOICES = [
('1', '项目接口'),
('2', '外部接口')]
project = models.ForeignKey('Project',
on_delete=models.CASCADE,
help_text='项目id',
verbose_name='项目id',
related_name='interfaces')
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(verbose_name='接口类型',
help_text='接口类型',
max_length=40,
choices=CHOICES,
default='1')
# 扩展,接口的说明,接口字段的参数
def __str__(self):
return self.url
class Meta:
db_table = 'tb_interface'
verbose_name = '接口表'
verbose_name_plural = verbose_name
b、序列化器类设计
class NestTestStepSerializer(ModelSerializer):
"""嵌套测试步骤序列化器"""
class Meta:
model = TestStep
fields = ['id', 'title']
class InterfaceSerializer(ModelSerializer):
steps = NestTestStepSerializer(many=True, read_only=True, source='teststep_set')
class Meta:
model = Interface
fields = '__all__'
def validate(self, attrs):
url = attrs.get('url')
type_ = attrs.get('type')
if type_ == '2':
if not url.startswith('http'):
raise serializers.ValidationError('外部接口的url需要完整的url,必须以http或者https开头')
return attrs
获取接口的列表信息时:还需要将接口的下用例信息获取出来
c、视图类设计
5、环境模块设计
class TestEnv(models.Model):
"""测试坏境表"""
name = models.CharField(max_length=150, help_text='环境名称', verbose_name='环境名称')
project = models.ForeignKey(Project,
on_delete=models.CASCADE,
help_text='项目id',
verbose_name='项目id')
global_variable = models.JSONField(help_text='全局变量',
verbose_name='全局变量',
default=dict,
null=True)
debug_global_variable = models.JSONField(help_text='debug模式全局变量',
verbose_name="debug模式全局变量",
default=dict,
null=True)
db = models.JSONField(help_text='数据库配置',
verbose_name='数据库配置',
default=list,
null=True,blank=True)
host = models.CharField(help_text='base_url地址',
verbose_name='base_url地址',
max_length=100,
null=True,blank=True)
headers = models.JSONField(help_text='请求头',
verbose_name='请求头',
default=dict,
null=True, blank=True)
global_func = models.TextField(help_text='全局工具函数',
verbose_name='全局工具函数',
default=open('./utils/global_func.py', 'r',
encoding='utf-8').read(),
null=True,blank=True)
def __str__(self):
return self.name
class Meta:
db_table = 'tb_testenv'
verbose_name = '接口表'
verbose_name_plural = verbose_name
6、DRF中的通用过滤
除了能够覆盖默认查询集之外,REST 框架还包括对通用过滤后端的支持,允许您轻松构建复杂的搜索和过滤器。
6.1、设置过滤器后端
可以使用设置全局设置默认过滤器后端DEFAULT_FILTER_BACKENDS。例如。
a、要使用DjangoFilterBackend,请先安装django-filter
pip install django-filter
注意djoango-filter仅支持:
● Python: 3.6,3.7,3.8
● Django: 2.2, 3.1,3.2
● DRF: 3.10+
b、注册
INSTALLED_APPS = [
...
'django_filters',
...
]
c、配置
REST_FRAMEWORK = {
...
...
# 过滤
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
d、使用
在后端类视图或者视图集中添加filterset_fields属性即可实现指定字段过滤,例如改写环境管理视图集
如下:
class EnvViewSet(ModelViewSet):
queryset = TestEnv.objects.all()
serializer_class = EnvSerializer
filterset_fields = ['name','project']
不需要在复写get_queryset方法手动过滤,就可以通过url/test_envs/?project=1访问过滤数据了。
注意:当使用外键字段过滤时,如果级联模式是删除,则使用不存在的数据过滤会返回400响应。例如上面的
视图如果使用不存在的项目id过滤返回结果如下:
http://127.0.0.1:8000/test_envs?project=2