3.平台数据模型设计
大约 5 分钟学习笔记测试平台开发
一、 数据库配置
1. 搭建 MySQL 数据库
2. 创建数据库
CREATE DATABASE `course_autotp` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
3. 安装 pymysqlclient 模块
# 链接 mysql 数据库需要此模块,此模块安装不了的,参考附录的方法
pip install mysqlclient
4. 配置 数据库参数
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'course_autotp', # 数据库名称
'USER': 'root', # 用户名
'PASSWORD': 'xxxx', # 密码
'HOST': '158.247.205.137',
'PORT': '3306',
'TEST': {
'CHARSET': 'utf8', # 数据库的编码配置
'COLLATION': 'utf8_general_ci',
}
}
}
二、 数据库设计
1. 一对一 关系
1 对 1 就是 1 个模型关联另一个模型,他们之间的关系是 1 对 1
一对一关联与多对一关联非常类似。若在模型中定义了 OneToOneField ,该模型的实例只需通过其属 性就能访问关联对象
class EntryDetail(models.Model):
entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
details = models.TextField()
ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.
不同点在于 “反向” 查询。一对一关联所关联的对象也能访问 Manager 对象,但这个 Manager 仅代表 一个对象,而不是对象的集合(QuerySet):
e = Entry.objects.get(id=2)
e.entrydetail # returns the related EntryDetail object
若未为关联关系指定对象,Django 会抛出 DoesNotExist 异常。
实例能通过为正向关联指定关联对象一样的方式指定给反向关联:
e.entrydetail = ed
2. 模型代码设计
其中,request,step 和 config 参考 HR 对应部分的字段,由于其中会出现很多嵌套字段,所以 1 层的字段 就用 json 数据类型来代替
from django.db import models
class Config(models.Model):
name = models.CharField('名称', max_length=128)
# 可 null 可空白
base_url = models.CharField('IP/域名', max_length=512, null=True, blank=True)
variables = models.JSONField('变量', null=True)
parameters = models.JSONField('参数', null=True) # 用于参数化
verify = models.BooleanField('https校验', default=False)
export = models.JSONField('用例返回值', null=True)
def __str__(self):
return self.name
class Step(models.Model):
# 同模型中,两个字段关联一个模型时,需要指定 related_name, 且名字不能相同
# 属于哪个用例
belong_case = models.ForeignKey('Case', on_delete=models.CASCADE, related_name='test_steps')
# 引用那条用例
linked_case = models.ForeignKey('Case', on_delete=models.SET_NULL, null=True, related_name='linked_steps')
name = models.CharField('名称', max_length=128)
variables = models.JSONField('变量', null=True)
extract = models.JSONField('请求返回值', null=True)
validate = models.JSONField('校验项', null=True)
setup_hooks = models.JSONField('初始化', null=True)
teardown_hooks = models.JSONField('清除', null=True)
def __str__(self):
return self.name
class Request(models.Model):
method_choices = ( # method 可选字段, 二维元组
(0, 'GET'), # 参数 1 : 保存在数据库中的值 ,参数 2 : 对位显示的值
(1, 'POST'),
(2, 'PUT'),
(3, 'DELETE'),
)
step = models.OneToOneField(Step, on_delete=models.CASCADE, null=True, , related_name='testrequest')
method = models.SmallIntegerField('请求方法', choices=method_choices, default=0)
url = models.CharField('请求路径', default='/', max_length=1000)
params = models.JSONField('url参数', null=True)
headers = models.JSONField('请求头', null=True)
cookies = models.JSONField('cookies', null=True)
data = models.JSONField('data参数', null=True)
json = models.JSONField('json参数', null=True)
def __str__(self):
return self.url
class Case(models.Model):
config = models.OneToOneField(Config, on_delete=models.DO_NOTHING)
suite = models.ForeignKey('Suite', on_delete=models.DO_NOTHING, null=True)
file_path = models.CharField('用例文件路径', max_length=1000, default='demo_case.json')
def __str__(self):
return self.config.name
class Suite(models.Model):
config = models.OneToOneField(Config, on_delete=models.DO_NOTHING)
file_path = models.CharField('套件文件路径', max_length=1000, default='demo_suite.json')
def __str__(self):
return self.config.name
3. 同步数据库
生成 数据库 同步 文件
python manage.py makemigrations
同步数据库
python manage.py migrate
三、 反向查询概念解析
1. 正向查询
模型查询其关联的项目叫做正向查询(外键定义在模型)
例如:步骤查询其所在的用例
# test.py
class TestRelatedQuery(TestCase):
def setUp(self) -> None:
# 创建套件和用例
self.config = Config.objects.create(name='用例1')
self.case = Case.objects.create(config=self.config)
self.config_suite = Config.objects.create(name='套件1')
self.suite = Suite.objects.create(config=self.config_suite)
def test_case_suite(self):
# 用例关联套件
self.case.suite = self.suite
# 保存数据库
self.case.save()
print(self.case.suite) # 正向查询-- 查询所属套件
print(self.case.config) # 正向查询 -- 查询配置
2. 反向查询
反过来,项目查询下面的模型叫做反向查询,通过反向查询的结果 QuerySet
未指定 related_name 时
多对多 或 多对一
modelobj.field_set.all()
一对一
modelobj.field
class TestRelatedQuery(TestCase):
def setUp(self) -> None:
# 创建套件和用例
self.config = Config.objects.create(name='用例1')
self.case = Case.objects.create(config=self.config)
self.config_suite = Config.objects.create(name='套件1')
self.suite = Suite.objects.create(config=self.config_suite)
def test_case_suite(self):
self.case.suite = self.suite # 用例关联套件
self.case.save() # 保存数据库
# 反向查询 --- 多对一 或 多对多
# 套件查询关联的用例 --- 数据对象.多方属性_set.all() --- 返回的是 QuerySet(查询集)
print(self.suite.case_set.all())
# 反向查询 --- 一对一
# 配置对应的用例 --- 数据对象.反向关系模型小写
print(self.config.case)
方式 2:指定 related_name 时
modelobj.related_name.all()
class TestRelatedQuery(TestCase):
def setUp(self) -> None:
# 创建套件和用例
self.config = Config.objects.create(name='用例1')
self.case = Case.objects.create(config=self.config)
self.config_suite = Config.objects.create(name='套件1')
self.suite = Suite.objects.create(config=self.config_suite)
def test_step_case(self):
self.step = Step.objects.create(belong_case=self.case, name='步骤1')
Step.objects.create(belong_case=self.case, name='步骤2')
Step.objects.create(belong_case=self.case, name='步骤3')
# 多对多 反向查询
print(self.case.test_steps.all())
def test_step_request(self):
self.step = Step.objects.create(belong_case=self.case, name='步骤1')
self.request = Request.objects.create(url='/demo/example', step=self.step)
# 一对一 关系反向查询
print(self.step.testrequest)
四、 json 字段操作
1、 增
class TestJsonOperate(TestCase):
def test_add(self):
req1 = Request.objects.create(url='/demo1', data={'name': '小明', 'age': '18', 'addr': '新世纪大道'})
print(req1.data)
req2 = Request.objects.create(url='/demo1', params={'name': '小明', 'age': '18', 'addr': '新世纪大道'})
print(req2.params)
2. 改
def test_update(self):
req1 = Request.objects.create(url='/demo1', data={'name': '小明', 'age': '18', 'addr': '新世纪大道'})
# 整体修改
req1.data = {'city': 'beijing'}
req1.save()
print(req1.data)
# 局部修改
req1.data['name'] = '小红'
req1.save()
print(req1.data)
3. 删
def test_delete(self):
req1 = Request.objects.create(url='/demo1', data={'name': '小明', 'age': '18', 'addr': '新世纪大道'})
req1.data = None # sql 的 none
req1.save()
print(req1.data)
# 查询的时候关系 字段 等于 sql 的 null
res = Request.objects.filter(data__isnull=True)
print(res)
req1.data = Value('null') # json 的 none
req1.save()
# 查询的关系 字段 等于 json 的 null
res = Request.objects.filter(data=None)
print(res)
4. 查
def test_query(self):
req1 = Request.objects.create(url='/demo1', data={'name': '小明', 'age': '18', 'addr': '新世纪大道','father':{'age':40}})
res = Request.objects.filter(data__father__age=40)
print(res)