一、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