接口平台测试开发--day16
一、pycharm 从git拉取代码
- 1、VCS--Get Versoin Controll
- 2、
具体配置内容
二、执行manage.py
1、pycharm路径
- 2、创建项目startapp +项目名称
- 例如:startapp sksystem
- 3、为新创建的项目新增urls.py
- earth/urls.py 增加路径
1 from django.contrib import admin 2 from django.urls import path, include 3 from sksystem import urls as sksUrls 4 from example import urls as urls 5 6 7 urlpatterns = [ 8 path('admin/', admin.site.urls), 9 path('example/',include(urls)), 10 path('api/', include(sksUrls)), # 例子url,访问的时候就是/example/book 11 ]
或者这样修改,将不用的example去除
1 from django.contrib import admin 2 from django.urls import path, include 3 4 #from sksystem import urls 5 6 urlpatterns = [ 7 path('admin/', admin.site.urls), 8 path('api/', include(urls)), # 例子url,访问的时候就是/example/book 9 ]
4、settings.py 增加新增的项目
三、数据库设计:
models.py
1 from django.db import models 2 from utils import tools 3 from earth import settings 4 5 6 # Create your models here. 7 8 9 class BaseModel(models.Model): 10 '''公共字段''' 11 is_delete_choice = ( 12 (0, '删除'), 13 (1, '正常') 14 ) 15 is_delete = models.SmallIntegerField(choices=is_delete_choice, default=1, verbose_name='是否被删除') 16 create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) # auto_now_add的意思,插入数据的时候,自动取当前时间 17 update_time = models.DateTimeField(verbose_name='修改时间', auto_now=True) # 修改数据的时候,时间会自动变 18 19 class Meta: 20 abstract = True # 只是用来继承的,不会创建这个表 21 22 23 class User(BaseModel): 24 '''用户表''' 25 phone = models.CharField(verbose_name='手机号', max_length=11, unique=True) 26 email = models.EmailField(verbose_name='邮箱', max_length=25, unique=True) 27 password = models.CharField(verbose_name='密码', max_length=32) 28 username = models.CharField(verbose_name='昵称', default='Python小学生', max_length=20) 29 30 @staticmethod 31 def make_password(raw_password): 32 '''生成密码''' 33 before_password = '%s%s' % (raw_password, settings.SECRET_KEY) # 生成密码的算法,可以自己改 34 after_password = tools.md5(before_password) 35 return after_password 36 37 def set_password(self, raw_password): 38 '''设置密码''' 39 self.password = self.make_password(raw_password) 40 41 def check_password(self, raw_password): 42 '''校验登录密码''' 43 return self.make_password(raw_password) == self.password 44 45 def __str__(self): 46 return self.username 47 48 class Meta: 49 verbose_name = '用户表' 50 verbose_name_plural = verbose_name 51 db_table = 'user' 52 53 class Parameter(BaseModel):#继承BaseModel 54 '''全局参数表''' 55 name = models.CharField(verbose_name='参数名', max_length=100, unique=True)#unique=True 唯一 56 desc = models.CharField(verbose_name='描述', max_length=200, null=True)#null=True允许传空 57 value = models.CharField(verbose_name='参数值', max_length=100) 58 59 def __str__(self): 60 return self.name 61 62 class Meta: 63 verbose_name = '全局参数' 64 verbose_name_plural = verbose_name 65 db_table = 'parameter' 66 ordering = ['-id'] # 按照id倒排。 67 68 69 class Project(BaseModel): 70 '''项目表''' 71 name = models.CharField(verbose_name='项目名', max_length=100, unique=True) 72 desc = models.CharField(verbose_name='描述', max_length=200, null=True) 73 host = models.CharField(verbose_name='域名', max_length=1024) 74 user = models.ForeignKey(User, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='创建者') 75 #on_delete=models.DO_NOTHING 当删除的时候不做任何事情 db_constraint=False 不是真正的去创建外键 76 77 def __str__(self): 78 return self.name 79 80 class Meta: 81 verbose_name = '项目表' 82 verbose_name_plural = verbose_name 83 db_table = 'project' 84 ordering = ['-id'] # 按照id倒排。 85 86 87 class Interface(BaseModel): 88 '''接口''' 89 name = models.CharField(verbose_name='接口名称', max_length=100, unique=True) 90 uri = models.CharField(verbose_name='接口路径', max_length=1024) 91 params = models.CharField(verbose_name='默认参数', max_length=2048,null=True,blank=True) 92 headers = models.CharField(verbose_name='默认Headers', max_length=2048,null=True,blank=True) 93 user = models.ForeignKey(User, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='创建者') 94 project = models.ForeignKey(Project, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='归属项目') 95 96 def __str__(self): 97 return self.name 98 99 class Meta: 100 verbose_name = '接口表' 101 verbose_name_plural = verbose_name 102 db_table = 'interface' 103 ordering = ['-id'] # 按照id倒排。 104 105 106 class Case(BaseModel): 107 '''用例表''' 108 title = models.CharField(verbose_name='用例标题', max_length=100) 109 project = models.ForeignKey(Project, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='归属项目') 110 interface = models.ForeignKey(Interface, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='接口') 111 user = models.ForeignKey(User, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='创建用户') 112 method_choice = ( 113 (1, 'POST'), 114 (2, 'GET'), 115 (3, 'DELETE'), 116 (4, 'PUT'), 117 ) 118 method = models.SmallIntegerField(choices=method_choice, verbose_name='请求方式') 119 120 cache_field = models.CharField(verbose_name='缓存字段', max_length=128, null=True, blank=True)#null=True,可能为空 blank=True 可能不传 121 122 check = models.CharField(verbose_name='校验点', max_length=512) 123 params = models.CharField(verbose_name='请求参数', max_length=2048, null=True, blank=True) 124 headers = models.CharField(verbose_name='请求头信息', max_length=2048, null=True, blank=True) 125 is_json = models.BooleanField(verbose_name='参数是否是json', default=False) 126 json = models.CharField(verbose_name='json类型参数', max_length=2048, null=True, blank=True) 127 status_choice = ( 128 (1, '通过'), 129 (2, '未运行'), 130 (3, '运行中'), 131 (999, '失败') 132 ) 133 status = models.SmallIntegerField(choices=status_choice, verbose_name='用例状态', 134 default=2) # 记录上一次的状态 每次执行后需要更新下这个表的这个字段 135 report_batch = models.CharField(verbose_name='最后一次执行的批次号', null=True, max_length=512, blank=True) 136 def __str__(self): 137 return self.name 138 139 class Meta: 140 verbose_name = '用例表' 141 verbose_name_plural = verbose_name 142 db_table = 'case' 143 ordering = ['-id'] # 按照id倒排 144 145 146 class CaseCollection(BaseModel): 147 '''用例集合''' 148 name = models.CharField(verbose_name='集合名', max_length=100, unique=True) 149 desc = models.CharField(verbose_name='描述', max_length=200, null=True) 150 user = models.ForeignKey(User, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='创建者') 151 project = models.ForeignKey(Project, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='归属项目') 152 report_batch = models.CharField(verbose_name='最后一次执行的批次号', null=True, max_length=512, blank=True) 153 status_choice = ( 154 (2, '未运行'), 155 (3, '运行中'), 156 (4, '执行完毕') 157 ) 158 status = models.SmallIntegerField(choices=status_choice, verbose_name='用例状态', 159 default=2) 160 case = models.ManyToManyField(Case,verbose_name='集合下的用例') 161 162 163 def __str__(self): 164 return self.name 165 166 class Meta: 167 verbose_name = '用例集合表' 168 verbose_name_plural = verbose_name 169 db_table = 'case_collection' 170 ordering = ['-id'] # 按照id倒排 171 class Report(BaseModel): 172 '''用例报告表''' 173 url = models.CharField(verbose_name='请求URL', max_length=1024) 174 project = models.ForeignKey(Project, verbose_name='项目', on_delete=models.DO_NOTHING, db_constraint=False) 175 title = models.CharField(verbose_name='用例名称', max_length=100) 176 params = models.CharField(verbose_name='请求参数', max_length=2048) 177 response = models.CharField(verbose_name='接口返回值结果', max_length=2048) 178 case = models.ForeignKey(Case, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='结果所属用例') 179 case_collection = models.ForeignKey(CaseCollection, on_delete=models.DO_NOTHING, db_constraint=False, 180 verbose_name='结果所属集合', null=True) 181 batch = models.CharField(verbose_name='批次', null=True, max_length=128) # 用于区分运行的第几批集合的用例 182 reason = models.CharField(verbose_name='失败原因', null=True, max_length=128, blank=True) 183 status_choice = ( 184 (1, '通过'), 185 (999, '失败') 186 ) 187 duration = models.IntegerField(verbose_name='用例耗时') 188 status = models.SmallIntegerField(choices=status_choice, verbose_name='用例结果状态') 189 user = models.ForeignKey(User, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='运行用户') 190 191 class Meta: 192 verbose_name = '用例报告表' 193 verbose_name_plural = verbose_name 194 db_table = 'report' 195 ordering = ['-id'] 196 class CasePremise(BaseModel): 197 '''依赖用例的关系表''' 198 case = models.ForeignKey(Case, verbose_name='用例id', on_delete=models.DO_NOTHING, db_constraint=False, unique=False,related_name='case') 199 premise_case = models.ForeignKey(Case, verbose_name='被依赖用例的id', on_delete=models.DO_NOTHING, db_constraint=False, 200 unique=False,related_name='premise_case') 201 202 def __str__(self): 203 return self.case 204 205 class Meta: 206 unique_together = ('case', 'premise_case') # 联合主键,一个case对另外一个case只能依赖一次 207 verbose_name = '依赖关系表' 208 verbose_name_plural = verbose_name 209 db_table = 'case_premise'
生成数据库:
1、makemigrations skssystem
2、migrate skssystem
3、生成结果如图:
四、数据库test——练习
- 在项目下创建文件model_test.py
- 复制如下内容到文件中model_test.py
1 import django, os 2 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'earth.settings') # 设置django的配置文件 3 django.setup() 4 from skssystem import models
练习一、外键操作练习
- user表增加一条内容,
- pycharm--database 增加数据方式
然后model_test.py 内容如下
1 user_obj = models.User.objects.get(id=1) 2 data = { 3 'name':'外键联系', 4 'desc':'描述', 5 'host':'http://127.0.0.1:8022', 6 'user':user_obj 7 8 } 9 models.Project.objects.create(**data)
运行后,project 表中有一条内容
练习二、正向查询
1 project_obj = models.Project.objects.get(id=1) 2 print(project_obj)#返回项目名称 3 print(project_obj.user.nick)
练习三、反向查询
1 u_obj = models.User.objects.get(id=1) 2 print(u_obj.project_set.all())
练习四、删除--现象:project 表数据被删除
1 # 外键删除 2 models.Project.objects.get(id=1).delete() 3 4 # 反向删除 5 u_obj = models.User.objects.get(id=1) 6 u_obj.project_set.all().delete()
练习五、外键自关联
1、使用database 中使用sql语句插入数据
2、输入内容然后执行操
3、外键操作
# 外键自关联 models.CasePremise.objects.create(case_id=1,premise_case_id=2) # 查询 case_obj = models.Case.objects.get(id=1) # 获取id为1 的用例信息 # CasePremise # case_obj.case.all() == select * from CasePremise where case_id= 1; qs = case_obj.case.all() # all() 返回的是一个列表的qs # [case_id为1的CasePremise数据] for item in qs: # qs实际是CasePremise的qs # item 是CasePremise 依赖数据的对象 print(item.case.title) print(item.premise_case.id)
多对多
1 # INSERT INTO `case_collection`(`id`, `is_delete`, `create_time`, `update_time`, `name`, `desc`, `report_batch`, `status`, `project_id`, `user_id`) VALUES (1, 1, '2020-02-12 22:08:04.594509', '2020-02-12 22:08:04.594617', '测试平台回归', '登录和项目的回归', 'b4a64581-5805-49d5-8991-20c34656e07b', 4, 1, 2); 2 # 用例集合和用例是多对多的关系 3 # A集合和B集合 4 # A用例和B用例 5 # A集合-- A用例和B用例 6 # B集合-- A用例和B用例 7 case_obj_A = models.Case.objects.get(id=1)#用例A 8 case_obj_B = models.Case.objects.get(id=2)#用例B 9 coll_obj_A=models.CaseCollection.objects.get(id=1)#集合A 10 print(case_obj_A,case_obj_B,coll_obj_A) 11 #通过集合中case字段创建多对多的创建 12 coll_obj_A.case.add(case_obj_A)#通过add()方法,创建多对多的映射关系 13 coll_obj_A.case.add(case_obj_B) 14 coll_obj=models.CaseCollection.objects.get(id=1)#集合A 15 coll_obj.case.add(1)#创建时通过id 的方式也可以
****case_collection_case 表格中会出现两条数据
多对多创建
1 case_obj_A = models.Case.objects.get(id=1) # 获取用例A 2 case_obj_B = models.Case.objects.get(id=2) # 获取用例B 3 coll_obj = models.CaseCollection.objects.get(id=1) # 获取集合 4 coll_obj.case.add(case_obj_B) # 通过add方法 创建多对多映射关系 5 coll_obj.case.add(case_obj_A) # 通过add方法 创建多对多映射关系 6 coll_obj.case.add(1) # 创建时 通过id创建 也可以
多对多--查询
1 case_obj_A = models.Case.objects.get(id=1) # 获取用例A 2 case_obj_B = models.Case.objects.get(id=2) # 获取用例B 3 coll_obj = models.CaseCollection.objects.get(id=1) # 获取集合 4 print('正向查询',case_obj_A.case.all()) 5 print('反向查询',case_obj_A.casecollection_set.all())
删除--多对多的关系
1 case_obj_A = models.Case.objects.get(id=1) # 获取用例A 2 case_obj_B = models.Case.objects.get(id=2) # 获取用例B 3 coll_obj = models.CaseCollection.objects.get(id=1) # 获取集合 4 coll_obj.case.clear() # 清除掉所有和集合有关的用例关系 5 coll_obj.case.remove(1) # 通过用例id 进行删除 6 coll_obj.case.remove(case_obj_B) # 通过用例id 进行删除
更新--多对多
1 case_obj_A = models.Case.objects.get(id=1) # 获取用例A 2 case_obj_B = models.Case.objects.get(id=2) # 获取用例B 3 coll_obj = models.CaseCollection.objects.get(id=1) # 获取集合 4 coll_obj.case.set([2]) # 将用例id为1和2的和集合建立关系
五、接口开发--登录--退出登录--全局参数
1、将example/view.py 的login 复制到sksystems/views.py 下,并将导入的内容都复制
1 import time, django_redis,pickle 2 from django.views import View 3 from utils.custom_views import NbView, BaseView, PostView, GetView 4 from utils.tools import model_to_dict 5 from . import models, forms 6 from utils import const 7 from utils.custom_response import NbResponse 8 from utils.tools import md5 9 import json 10 11 class LoginView(View): 12 '''登录''' 13 def post(self, request): 14 user_form_obj = forms.LoginForm(request.POST) 15 if user_form_obj.is_valid(): 16 user = user_form_obj.cleaned_data['user'] 17 token = '%s%s' % (user.username, time.time()) 18 token = md5(token) 19 try: 20 redis = django_redis.get_redis_connection() 21 except: 22 raise Exception("连接不上redis,请检查redis!") 23 redis.set(const.token_prefix+token, pickle.dumps(user), const.token_expire) 24 return NbResponse(token=token, user=user.username) 25 else: 26 return NbResponse(-1, user_form_obj.error_format)
2、sksystem/urls.py 增加登录接口的路径
1 from django.urls import path 2 from . import views 3 urlpatterns = [ 4 path('login', views.LoginView.as_view()),#登录 5 ]
3、sksystem 目录下创建forms.py,将exampl/forms.py的登录的内容复制到sksystem/forms.py
1 from django.core.exceptions import ValidationError 2 from django.db.models import Q 3 from django.forms import ModelForm, Form 4 from django import forms 5 6 from . import models 7 from utils.tools import ExtendForm 8 9 class LoginForm(Form, ExtendForm): 10 username = forms.CharField(min_length=5, max_length=20, required=True) 11 password = forms.CharField(min_length=6, max_length=20, required=True) 12 13 def clean(self): 14 if not self.errors: # 校验errors里面是否有错误 15 username = self.cleaned_data['username'] 16 password = self.cleaned_data['password'] 17 user = models.User.objects.filter(Q(phone=username) | Q(email=username)) 18 if user: 19 user = user.first() 20 if user.check_password(password): 21 self.cleaned_data['user'] = user 22 return self.cleaned_data 23 else: 24 self.add_error('password','密码错误') 25 26 else: 27 self.add_error('username', '用户不存在')
4、修改settings.py下的redis的ip和密码
- 请求接口的过程
(1)earth/urls.py 也就是api
(2)sksystem/urls.py 也就是login
(3)sksystem/views.py loginview
5、用postman 请求接口
退出接口
(1)sksystem/views.py
1 class LogoutView(View): 2 '''退出''' 3 def post(self, request): 4 redis = django_redis.get_redis_connection() 5 redis.delete(const.token_prefix+request.META.get('HTTP_TOKEN')) 6 return NbResponse()
(2)sksystem/urls.py
1 path('logout', views.LogoutView.as_view()),#
(3)postman接口
全局参数接口
(1)sksystem/views.py
1 1 # 全局参数的接口。 2 2 class ParameterView(NbView): 3 3 search_field = ["name"] # 根据哪些字段来搜索 4 4 filter_field = [] # 根据哪些字段来搜索 5 5 model_class = models.Parameter # 用哪个model类 6 6 form_class = forms.ParameterForm # 用哪个form类
(3)sksystem/forms.py
1 class ParameterForm(ModelForm, ExtendForm): 2 class Meta: 3 model = models.Parameter 4 exclude = ['is_delete']
(4)sksystem/urls.py
1 path('parameter', views.ParameterView.as_view()),#全局操作
(5)postman