专栏首页测试游记测试开发进阶(三十四)

测试开发进阶(三十四)

数据库模型图

创建app

根据上面的数据库设计,创建9个app

  • configures
  • debugtalks
  • envs
  • interfaces
  • projects
  • reports
  • testsuits
  • testcases
  • user

完成注册

import sys
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'configures.apps.ConfiguresConfig',
    'debugtalks.apps.DebugtalksConfig',
    'envs.apps.EnvsConfig',
    'interfaces.apps.InterfacesConfig',
    'projects.apps.ProjectsConfig',
    'reports.apps.ReportsConfig',
    'testsuits.apps.TestsuitsConfig',
    'testcases.apps.TestcasesConfig',
    'user.apps.UserConfig',
]

抽象数据库基类

从数据库模型图可以看出,有很多部分都重复了

  • create_time
  • update_time
  • is_delete
from django.db import models


class BaseModel(models.Model):
    """
    数据库表公共字段
    """
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间", help_text="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间", help_text="更新时间")
    is_delete = models.BooleanField(default=False, verbose_name="逻辑删除", help_text="逻辑删除")

    class Meta:
        # 为抽象模型类, 用于其他模型来继承,数据库迁移时不会创建BaseModel表
        abstract = True
        verbose_name = "公共字段表"
        db_table = 'BaseModel'

default=False默认情况下不删除

各模块的模型

configures

# configures.models.Configures
from django.db import models
from utils.base_models import BaseModel


class Configures(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('配置名称', max_length=50, help_text='配置名称')
    interface = models.ForeignKey('interfaces.Interfaces',
                                  on_delete=models.CASCADE,
                                  related_name='configures',
                                  help_text='所属接口')
    author = models.CharField('编写人员', max_length=50, help_text='编写人员')
    request = models.TextField('请求信息', help_text='请求信息')

    class Meta:
        db_table = 'tb_configures'
        verbose_name = '配置信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

debugtalks

# debugtalks.models.DebugTalks
from django.db import models
from utils.base_models import BaseModel


class DebugTalks(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('debugtalk文件名称', max_length=200, default='debugtalk.py', help_text='debugtalk文件名称')
    debugtalk = models.TextField(null=True, default='#debugtalk.py', help_text='debugtalk.py文件')
    project = models.OneToOneField('projects.Projects', on_delete=models.CASCADE,
                                   related_name='debugtalks', help_text='所属项目')

    class Meta:
        db_table = 'tb_debugtalks'
        verbose_name = 'debugtalk.py文件'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

interfaces

# interfaces.models.Interfaces
from django.db import models
from utils.base_models import BaseModel


class Interfaces(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('接口名称', max_length=200, unique=True, help_text='接口名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='interfaces', help_text='所属项目')
    tester = models.CharField('测试人员', max_length=50, help_text='测试人员')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, help_text='简要描述')

    class Meta:
        db_table = 'tb_interfaces'
        verbose_name = '接口信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

projects

# projects.models.Projects
from django.db import models
from utils.base_models import BaseModel


class Projects(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('项目名称', max_length=200, unique=True, help_text='项目名称')
    leader = models.CharField('负责人', max_length=50, help_text='项目负责人')
    tester = models.CharField('测试人员', max_length=50, help_text='项目测试人员')
    programmer = models.CharField('开发人员', max_length=50, help_text='开发人员')
    publish_app = models.CharField('发布应用', max_length=100, help_text='发布应用')
    desc = models.CharField('简要描述', max_length=200, null=True, blank=True, default='', help_text='简要描述')

    class Meta:
        db_table = 'tb_projects'
        verbose_name = '项目信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

reports

# reports.models.Reports
from django.db import models
from utils.base_models import BaseModel


class Reports(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('报告名称', max_length=200, unique=True, help_text='报告名称')
    result = models.BooleanField('执行结果', default=1, help_text='执行结果')   # 1为成功, 0为失败
    count = models.IntegerField('用例总数', help_text='总用例数')
    success = models.IntegerField('成功总数', help_text='成功总数')
    html = models.TextField('报告HTML源码', help_text='报告HTML源码', null=True, blank=True, default='')
    summary = models.TextField('报告详情', help_text='报告详情', null=True, blank=True, default='')

    class Meta:
        db_table = 'tb_reports'
        verbose_name = '测试报告'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

testcases

# testcases.models.Testcases
from django.db import models
from utils.base_models import BaseModel


class Testcases(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('用例名称', max_length=50, unique=True, help_text='用例名称')
    interface = models.ForeignKey('interfaces.Interfaces', on_delete=models.CASCADE,
                                  help_text='所属接口')
    # include = models.ForeignKey('', on_delete=models.SET_NULL, null=True, related_name='testcases')
    include = models.TextField('前置', null=True, help_text='用例执行前置顺序')
    author = models.CharField('编写人员', max_length=50, help_text='编写人员')
    request = models.TextField('请求信息', help_text='请求信息')

    class Meta:
        db_table = 'tb_testcases'
        verbose_name = '用例信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

testsuits

# testsuits.models.Testsuits
from django.db import models
from utils.base_models import BaseModel


class Testsuits(BaseModel):
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField('套件名称', max_length=200, unique=True, help_text='套件名称')
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE,
                                related_name='testsuits', help_text='所属项目')
    # include = models.TextField(null=False)
    include = models.TextField('包含的接口', null=False, help_text='包含的接口')

    class Meta:
        db_table = 'tb_testsuits'
        verbose_name = '套件信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

projects需求

  • 删除项目时,只进行逻辑删除
  • 获取项目列表信息时,要求能获取此项目下的「接口总数」,「用例总数」,「配置总数」,「套件总数」,同时输出创建时间,格式为2019-11-05 11:43:00
  • 要求提供获取此项目下的所有项目名的接口
  • 要求提供获取此项目下的所有接口信息的接口

序列化器

from rest_framework import serializers
from .models import Projects
from debugtalks.models import DebugTalks
from interfaces.models import Interfaces


class ProjectModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Projects
        exclude = ('update_time', 'is_delete')

        extra_kwargs = {
            'create_time': {
                'read_only': True
            }
        }

    def create(self, validated_data):
        project_obj = super().create(validated_data)
        DebugTalks.objects.create(project=project_obj)

        return project_obj


class ProjectNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = Projects
        fields = ('id', 'name')


class InterfaceNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = Interfaces
        fields = ('id', 'name', 'tester')


class InterfacesByProjectIdSerializer(serializers.ModelSerializer):
    interfaces_set = InterfaceNameSerializer(read_only=True, many=True)

    class Meta:
        model = Projects
        fields = ('id', 'interfaces_set')

视图

继承 ModelViewSet

from rest_framework.viewsets import ModelViewSet
from rest_framework import permissions
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import NotFound

from . import serializer
from .models import Projects
from .utils import get_count_by_project
from interfaces.models import Interfaces


class ProjectsViewSet(ModelViewSet):
    """
    list:
    返回项目(多个)列表数据

    create:
    创建项目

    retrieve:
    返回项目(单个)详情数据

    update:
    更新(全)项目

    partial_update:
    更新(部分)项目

    destroy:
    删除项目

    names:
    返回所有项目ID和名称

    interfaces:
    返回某个项目的所有接口信息(ID和名称)
    """
    queryset = Projects.objects.filter(is_delete=False)
    serializer_class = serializer.ProjectModelSerializer
    permission_classes = (permissions.IsAuthenticated,)
    ordering_fields = ('id', 'name')

    def perform_destroy(self, instance):
        instance.is_delete = True
        instance.save()  # 逻辑删除

    @action(methods=['get'], detail=False)
    def names(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        serializer = serializer.ProjectNameSerializer(instance=queryset, many=True)
        return Response(serializer.data)

    @action(methods=['get'], detail=True)
    def interfaces(self, request, pk=None):
        interface_objs = Interfaces.objects.filter(project_id=pk, is_delete=False)
        one_list = []
        for obj in interface_objs:
            one_list.append({
                'id': obj.id,
                'name': obj.name
            })
        return Response(data=one_list)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            datas = serializer.data
            datas = get_count_by_project(datas)
            return self.get_paginated_response(datas)

        serializer = self.get_serializer(queryset, many=True)
        datas = serializer.data
        datas = get_count_by_project(datas)
        return Response(datas)

本文分享自微信公众号 - 测试游记(zx94_11),作者:zx钟

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Django的用户表创建(四)

    加入我们需要完成注册,那就需要把这三个字段username,password,email存入到数据库中 我们首先编写数据库相关的代码 因为Django框架功能齐...

    zx钟
  • 测试开发进阶(二十二)

    让图中的 Persons变为中文:修改 projects.models.Person保存后刷新页面

    zx钟
  • ARTS第二周

    假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

    zx钟
  • python3 __name__

    所以我们平常见到的__name__ == "__main__"就是指当前文件作为脚本运行时会发生的一些事情, 防止当前文件作为模块导入时运行自己不想运行的代码

    py3study
  • 一日一技:从列表中一次性筛选多个指定位置的数

    那么问题来了,我有一个Python里面,列表能不能也实现这个功能呢?假设有下面两个列表:

    青南
  • Django 2.1.7 runserver启动直接报错 django.core.exceptions.ImproperlyConfigured: Passing a 3-tuple to i...

    在其他办公电脑创建的Django项目 2.2.1 版本都可以直接 runserver 启动服务正常。 但是本地创建的项目,只要执行python3 manage...

    Devops海洋的渔夫
  • 快速理解微服务架构

    首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统WEB应用,来理解什么是微服务。 传统的WEB应用核心分为业务逻辑、适配器以及...

    用户4143945
  • java之spring之整合ssh

    github地址:https://github.com/Vincent-yuan/spring_ssh

    Vincent-yuan
  • python---爬取英雄联盟皮肤图片

    爬LOL的皮肤高清图片的大致步骤就是用selenium去爬取英雄联盟所以英雄的皮肤的url地址,然后在用requests库去将图片下载到本地。

    sjw1998
  • 微服务架构详解

    首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统WEB应用,来理解什么是微服务。

    技术zhai

扫码关注云+社区

领取腾讯云代金券