一、常见用法
(1)用法1
接口模型、测试用例模型
# 接口模型
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
# 测试用例
class TestStep(models.Model):
"""用例表"""
title = models.CharField(max_length=50, help_text='用例名称', verbose_name='用例名')
# 一个接口对应多个用例, 一个用例对应一个接口
interface = models.ForeignKey('projects.Interface', on_delete=models.CASCADE, help_text='接口', verbose_name='接口')
headers = models.JSONField(help_text='请求头', verbose_name='请求头', default=dict, blank=True)
request = models.JSONField(help_text='请求信息', verbose_name='请求信息', default=dict, blank=True)
file = models.JSONField(help_text='上传的文件参数', verbose_name='上传的文件', default=list, blank=True)
setup_script = models.TextField(help_text='前置脚本', verbose_name='前置脚本', default=setup_script, blank=True)
teardown_script = models.TextField(help_text='后置脚本', verbose_name='用例后置脚本 ', default=teardown_script,
blank=True)
def __str__(self):
return self.title
class Meta:
db_table = 'tb_test_step'
verbose_name = "测试步骤表"
verbose_name_plural = verbose_name
嵌套序列化器:
先搞清楚2个模型之间的关系,这里 Interface模型,也就是接口模型,跟测试用例其实是一对多的关系,一个接口可能有多个测试用例,一个测试用例只有一个接口。
那这个时候我想知道我这个接口关联了哪几个测试用例怎么办?(也就是说有几个测试用例涉及到了这个接口),那我们接口模型中又没有用例这个字段?怎么办?
我们需要新增一个字段 steps ,这个字段的数据从哪里获取?我们看到用例模型中有interface字段外键关联接口模型,所以我们通过嵌套序列化器,source指定=teststep_set。
如果一个模型 TestStep 有一个外键关联到另一个模型 Interface,那么DRF会自动为TestStep模型生成一个名为teststep_set的反向关联属性,用于对TestStep模型进行反向查询。在嵌套序列化器中,我们可以使用这个反向关联属性来指定需要序列化的字段。
当一个模型定义了 ForeignKey 或者 ManyToManyField 字段时,Django 会自动为这个模型添加一个反向关联属性,这个属性的名称是由 Django 自动生成的,默认为关联模型的小写名称加上 _set。
class NestTestStepSerializer(serializers.ModelSerializer):
"""嵌套测试步骤序列化器"""
class Meta:
model = TestStep
# 为啥只要id和title(前后端沟通交流)
fields = ['id', 'title']
class InterfaceSerializer(serializers.ModelSerializer):
"""
接口序列化器
"""
steps = NestTestStepSerializer(source='teststep_set', many=True, read_only=True)
class Meta:
model = Interface
fields = '__all__'
(2)用法2
接口模型、测试场景模型
# 用例表
class TestStep(models.Model):
"""用例表"""
title = models.CharField(max_length=50, help_text='用例名称', verbose_name='用例名')
# 一个接口对应多个用例, 一个用例对应一个接口
interface = models.ForeignKey('projects.Interface', on_delete=models.CASCADE, help_text='接口', verbose_name='接口')
headers = models.JSONField(help_text='请求头', verbose_name='请求头', default=dict, blank=True)
request = models.JSONField(help_text='请求信息', verbose_name='请求信息', default=dict, blank=True)
file = models.JSONField(help_text='上传的文件参数', verbose_name='上传的文件', default=list, blank=True)
setup_script = models.TextField(help_text='前置脚本', verbose_name='前置脚本', default=setup_script, blank=True)
teardown_script = models.TextField(help_text='后置脚本', verbose_name='用例后置脚本 ', default=teardown_script,
blank=True)
def __str__(self):
return self.title
class Meta:
db_table = 'tb_test_step'
verbose_name = "测试步骤表"
verbose_name_plural = verbose_name
# 测试场景/套件 中间表
class SceneData(models.Model):
"""场景/套件数据,中间表"""
step = models.ForeignKey('TestStep', help_text='步骤', verbose_name='步骤',
on_delete=models.PROTECT)
scene = models.ForeignKey(TestScene, help_text='场景', verbose_name='场景', on_delete=models.PROTECT)
sort = models.IntegerField(help_text='执行顺序', verbose_name='执行顺序',
blank=True)
def __str__(self):
return str(self.id)
class Meta:
db_table = 'tb_scene_data'
verbose_name = "场景步骤"
verbose_name_plural = verbose_name
setup_script = """
# 前置脚本(python):
# global_tools:全局工具函数
# data:用例数据
# env: 局部环境
# ENV: 全局环境
# db: 数据库操作对象
"""
teardown_script = """
# 后置脚本(python):
# global_tools:全局工具函数
# data:用例数据
# response:响应对象response
# env: 局部环境
# ENV: 全局环境
# db: 数据库操作对象
"""
序列化器:
场景中间表有 step用例、scene场景、sort执行顺序。我在场景中间表序列化器中新定义一个stepInfo,用来存储用例序列化器实例化出来的对象。
source='step',是啥意思?
因为第三张表中的step与 TestStep 是外键关联的,所以 NestTestStepSerializer用例序列化器 可以直接引用 别的模型中的字段。
class NestTestStepSerializer(serializers.ModelSerializer):
"""嵌套测试步骤序列化器"""
class Meta:
model = TestStep
# 为啥只要id和title(前后端沟通交流)
fields = ['id', 'title']
class TestSceneStepSerializer(serializers.ModelSerializer):
"""测试场景步骤序列化器"""
# 这是一个额外的字段, source代表意思是指定源,告诉他你是哪个字段。
stepInfo = NestTestStepSerializer(source='step', read_only=True)
class Meta:
model = SceneData
fields = '__all__'
(3)用法3
我们要在学生信息界面展示出该学生的成绩,就需要关联到成绩外键,需要在学生的序列化器中调用成绩序列化器
class Student(models.Model):
name = models.CharField(max_length=50, verbose_name="姓名")
age = models.IntegerField(verbose_name="年龄")
sex = models.BooleanField(default=False)
class Meta:
db_table = 'sch_student'
def __str__(self):
return self.name
class Achievement(models.Model):
score = models.DecimalField(default=0, max_digits=4, decimal_places=1, verbose_name="成绩")
student = models.ForeignKey(Student,on_delete=models.DO_NOTHING, related_name='s_achievement', db_constraint=False)
course = models.ForeignKey(Course,on_delete=models.DO_NOTHING, related_name='c_achievement', db_constraint=False)
create_dtime = models.DateTimeField(auto_created=datatime.now)
class Meta:
db_table = "sch_achievement"
def __str__(self):
return str(self.score)
class AchievementModelSerializer(serializers.ModelSerializer):
class Meta:
model = Achievement
fields = "__all__"
class StudentModelSerializer(serializers.ModelSerializer):
# 在序列化器中调用另一个序列化器,就是序列化器嵌套
s_achievement = AchievementModelSerializer()
class Meta:
model = Student
fields = ['id','name','s_achievement']
总结:
下面提到的一和多 就是表之间的关系是一对多还是多对一的意思。
第一个场景 是在一的一方去嵌套序列化器,所以source是用到多的一方的小写模型名+_set
第二个场景 是在多的一方去嵌套序列化器,source直接引用相关联的模型所对应的字段。
(4)用法4
(5)用法5
(6)用法6