当前位置: 首页 > news >正文

Django + Vue3 前后端分离技术实现自动化测试平台从零到有系列 <第三章> 之 基础架构搭建

基础架构搭建

  • 1、简介
  • 2、开发前准备
    • 2.1、本教程需要的基础:
    • 2.2、开发环境准备:
    • 2.3、数据库准备
    • 2.4、前一章节的代码:
  • 3、代码
    • 3.1、回顾前文
    • 3.2、新架构
    • 3.2、调整操作
    • 3.2、Django识别调整后的APP
  • 4、新增APP
    • 4.1、自动化测试APP
    • 4.2、系统管理APP
  • 5、数据
    • 5.1、表设计
    • 5.2、代码
      • 5.2.1、树递归
      • 5.2.2、models.py编写
      • 5.2.3、生成表
  • 6、总结&预告

1、简介

本章第一部份是后端Django项目按照第二章的架构设计将平台架构目录搭建完成;架构直观的表示在代码目录结构的调整;第二部分是自动化测试功能模块的表设计与创建;这是核心,也会是优先开发的部分。
这两部分组合成了整个项目架构基础,有了他们,后续的开发便顺畅了。

后面所有 模块 == APP(django项目使用 python manage.py startapp 创建的APP),后面常描述 ‘APP’,也可能一时不查写成了’模块’,希望理解

2、开发前准备

2.1、本教程需要的基础:

Python代码编写精通
Django 会写Demo
Vue3 + Element 会写Demo

基础欠些也没有关系,本文会细致的讲解用到的代码,按照一步一步来,也能实现;不懂的可以留言与私聊。

2.2、开发环境准备:

一台安装了下面东西电脑
Mysql 8
Python 3.6 +
Nodejs
Django 4 +
Pycharm
Vscode (开发前端用)

2.3、数据库准备

mysql8新增一个数据库apiauto,备用
字符集:utf8mb4
排序规则:utf8mb4_general_ci

在这里插入图片描述

2.4、前一章节的代码:

https://download.csdn.net/download/weixin_40331132/91955861

3、代码

3.1、回顾前文

下图为<第二章>内容,见图后端分为用户、自动化测试、系统管理三个大模块;项目架构按照三个模块进行模块化;在<第一章>已经新增了 users APP,还须再增加两个APP。

在这里插入图片描述
让我们再回顾<第一章>项目的层级目录:

apiauto/                        # 项目根目录(包含 manage.py 和应用目录)
├─ manage.py                    # Django 管理脚本,项目入口,可运行迁移、启动服务等
│
├─ apiauto/                     # 项目配置目录(和项目同名)
│   ├─ __init__.py              # Python 包标识(空文件即可)
│   ├─ settings.py              # 全局配置文件(数据库、应用、REST、JWT 等)
│   ├─ urls.py                  # 项目 URL 路由入口,分发到各个 app 的 urls.py
│   ├─ wsgi.py                  # WSGI 启动文件,传统部署(Gunicorn/Uwsgi 用)
│   └─ asgi.py                  # ASGI 启动文件,异步部署(Daphne/Uvicorn 用,支持 WebSocket)
│
└─ users/                       # 自定义应用(用户模块)├─ __init__.py              # Python 包标识├─ admin.py                 # Django Admin 后台配置(可注册用户模型)├─ apps.py                  # 应用配置,Django 自动识别 app├─ models.py                # 数据模型定义(ORM 对应数据库表)├─ serializers.py           # DRF 序列化器(定义注册、用户信息、修改密码等数据结构)├─ views.py                 # 视图(API 逻辑处理,例如注册、登录、获取用户信息)├─ urls.py                  # 当前 app 的路由(只负责本 app 的接口)└─ test.py                  # 单元测试文件(编写测试用例验证功能是否正确)  

明显的感觉他层级不明显,需要更容易明显的区分项目与APP的架构层级

3.2、新架构

在新增自动化测试、系统管理这两个APP前,

其中 users 是APP,与项目配置目录同一层级,为了区分与统一管理APP,在同级目录下增加一个apps目录,apps下放所有APP,users会移动过去。改动后目录如下:

apiauto/                        # 项目根目录(包含 manage.py 和应用目录)
├─ manage.py                    # Django 管理脚本,项目入口,可运行迁移、启动服务等
│
├─ apiauto/                     # 项目配置目录(和项目同名)
│   ├─ __init__.py              # Python 包标识(空文件即可)
│   ├─ settings.py              # 全局配置文件(数据库、应用、REST、JWT 等)
│   ├─ urls.py                  # 项目 URL 路由入口,分发到各个 app 的 urls.py
│   ├─ wsgi.py                  # WSGI 启动文件,传统部署(Gunicorn/Uwsgi 用)
│   └─ asgi.py                  # ASGI 启动文件,异步部署(Daphne/Uvicorn 用,支持 WebSocket)
│
└─ apps/                        # APPS集中管理目录   ├─ users/                   # 用户模块APP│   ├─ __init__.py          # Python 包标识(空文件即可)│   ├─ settings.py          # 全局配置文件(数据库、应用、REST、JWT 等)│   ├─ urls.py              # 项目 URL 路由入口,分发到各个 app 的 urls.py│   ├─ wsgi.py              # WSGI 启动文件,传统部署(Gunicorn/Uwsgi 用)│   └─ asgi.py              # ASGI 启动文件,异步部署(Daphne/Uvicorn 用,支持 WebSocket)├─ auto/                    # 自动化模块APP├─ sysmanages/              # 系统管理模块APP└─ ....                   

3.2、调整操作

1、在apiauto目录下新增apps目录

apiauto右击----New----Directory

在这里插入图片描述

弹出框中输入:apps,

在这里插入图片描述

按下 回车,创建apps目录如下图

在这里插入图片描述
2、将users APP移动到apps目录,

将users拖过去apps目录,确认即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2、Django识别调整后的APP

这里users APP移动了,已经在apps目录下了,项目运行仍会找原因来位置的users,它不存在原位置了,所以运行会开始报错,说:No module named ‘users’
在这里插入图片描述
因为APP移动,django找不到这个APP

解决方案很简单,在apiauto目录下的setting.py里增加一行代码:

import os, sys
sys.path.insert(0,  os.path.join(BASE_DIR, 'apps'))

增加到 “BASE_DIR = Path(file).resolve().parent.parent” 这行代码后面
在这里插入图片描述
添加这行后,项目运行成功了。
在这里插入图片描述

4、新增APP

4.1、自动化测试APP

现在增加APP需要进入apps目录下增加了
打开Terminal 编辑进,进入apps目录下
在这里插入图片描述

输入命令:

python ../manage.py startapp auto

在这里插入图片描述

auto是自动化测试模块的APP,接下来新增系统管理APP

4.2、系统管理APP

输入命令

python ../manage.py startapp sysmanage

在这里插入图片描述

到这里,整个平台的架构已经初步形成,

users:用户登录与注册、密码修改、三方登录、用户信息等相关的功能;
sysmanage:整个系统的管理,权限、日志、三方接入配置等;
auto: 核心功能,自动化测试的功能,主要有环境、接口、用例、套件、执行计划等的功能;

在这里插入图片描述
架构设计目录只是一部分,表设计不可或缺。
users模块的表继承了django的用户相的表,不需要设计
sysmanage,它可能会管到各个模块的表,自己未必有表,暂时搁置
下面便开始设计auto模块的表;

5、数据

5.1、表设计

一个完整的接口自动化测试平台,需要以下这些表

项目表:公司不止一个项目,不同项目之间的数据需要隔离
环境配置表:每个项目不止一个环境,一般有SIT、UAT、性能、线上环境
接口树表:树结构可以让人按功能、模块管理对应接口,以Sawwage作参考
用例树表:树结构可以让人按功能、模块管理对应用例
接口表:接口数据,加上mock自段
用例表:用例数据、检查点、执行状态等
前置后置执行步骤表:关联用例表,是用例执行前或后需要执行的脚本方法(关键字),功能强大;
套件表:用例执行集合
执行计划表:可以是套件的集合、定时、统计数据、
用例执行记录表:测试报告
套件执行记录表:统计报告
计划执行记录表:统计报告
前置后置执行记录表:测试报告
自定义脚本表:存放平台用户编写的脚本,编写完成后会生成关键字在用例中选择到

表的ER图设计如下:
在这里插入图片描述

5.2、代码

5.2.1、树递归

通过ER图可以看出,有两个树模型:接口树、用例树。
他们是自已外键自已,等于递归模型;
所以要先做了一个表数据自我递归小工具代码。

问递归是啥?各位如果递归不懂的,可以去力扣或其他的教程中找找答案。

在这里插入图片描述
在这里插入图片描述
在项目根目录下新增一个目录utils
项下添加个mixins.py文件里面增加代码

class TreeMixin:"""给自关联模型提供树形结构功能"""def to_dict(self):"""转换为 dict 节点"""return {"id": self.id,"name": self.name,"children": [child.to_dict() for child in self.children.filter(is_deleted=False)]}@classmethoddef build_tree(cls, queryset, parent=None):"""构建树形结构 (JSON 风格),自动过滤 is_deleted=True 的节点"""nodes = queryset.filter(parent=parent, is_deleted=False)return [node.to_dict() for node in nodes]@classmethoddef print_tree(cls, queryset, parent=None, indent=0):"""打印缩进树,调试用,自动过滤 is_deleted=True"""nodes = queryset.filter(parent=parent, is_deleted=False)for node in nodes:print(" " * indent + f"- {node.name}")cls.print_tree(queryset, node, indent + 2)

在这里插入图片描述

这个工具写完了后,后面大用,很多递归模型可以继承他。然后完成模型数据的自我递归,输出序列数据。
下面便开始对ER图的表进行Model化了。

5.2.2、models.py编写

各位可以回看一下ER图,其中每一个表,都有is_delete、created_at 、updated_at 、created_by 等字段;我们可以将这几个字段抽取出来成一个BaseModel,使用abstract = True标识这个Model不会生成表。

models.py文件做什么的?大家可以了解一下Django的ORM相关的知识。 死记住理论后,照搬下面代码生成数据库表进行理解。
死记理论,只记他的运行逻辑顺序便好,不是记ORM有众多关键字哈,关键字了解一下即可。

代码比较长,请诸位结合ER图喝着茶细品~

from django.db import models
# Create your models here.from django.contrib.auth.models import User
# 引用工具树
from utils.mixins import TreeMixinclass BaseModel(models.Model):"""抽象基类:给所有表提供通用字段"""is_delete = models.BooleanField(default=False, verbose_name="是否删除")created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="创建人")class Meta:abstract = True  # 不会生成表,仅供继承class Project(BaseModel):"""项目"""pro_name = models.CharField(max_length=100, null=True, unique=True, verbose_name='项目名称,唯一校验')description = models.TextField(null=True,verbose_name="项目描述")class Meta:managed = Truedb_table = 'auto_project'def __str__(self):return '{id:%d, projectname:%s, description:%s}' \% (self.id, str(self.projectname), str(self.description))class Environment(BaseModel):"""测试环境配置"""name = models.CharField(max_length=50, unique=True, verbose_name="环境名称")pro = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="test_env", verbose_name="项目其下环境")base_url = models.URLField(verbose_name="基础 URL")headers = models.JSONField(blank=True, null=True, verbose_name="公共请求头")db_config = models.JSONField(blank=True, null=True, verbose_name="数据库配置")env_params = models.JSONField(blank=True, null=True, verbose_name="环境变量配置")class Meta:db_table = "auto_environment"  # 表名verbose_name = "测试环境"verbose_name_plural = "测试环境"indexes = [models.Index(fields=["name"]),  # 添加索引]def __str__(self):return self.nameclass Apinode(BaseModel, TreeMixin):"""接口树,管理接口,此表自我递归,继承TreeMixin的方法"""name = models.CharField(max_length=200, null=False, verbose_name='node名称')parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, related_name="children")pro = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="api_node", verbose_name="项目下节点")class Meta:managed=Truedb_table = 'auto_api_node'def __str__(self):return self.nameclass API(BaseModel):"""接口信息表"""name = models.CharField(max_length=100, verbose_name="接口名称")path = models.CharField(max_length=200, verbose_name="接口路径")method = models.CharField(max_length=10,choices=[("GET", "GET"), ("POST", "POST"), ("PUT", "PUT"), ("DELETE", "DELETE"), ("PATCH", "PATCH")],verbose_name="请求方法")headers = models.JSONField(blank=True, null=True, verbose_name="请求头")params = models.JSONField(blank=True, null=True, verbose_name="Query 参数")body = models.JSONField(blank=True, null=True, verbose_name="请求体")response = models.JSONField(blank=True, null=True, verbose_name='返回结果')node = models.ForeignKey(Apinode, on_delete=models.DO_NOTHING, related_name="test_api", verbose_name="接口树管理接口")ismock = models.IntegerField(default=0, null=True, verbose_name='是否mock, 0为否,1为是')class Meta:db_table = "auto_api"verbose_name = "接口"verbose_name_plural = "接口"indexes = [models.Index(fields=["name"]),models.Index(fields=["method"]),]def __str__(self):return f"{self.name} [{self.method}]"class Casenode(BaseModel, TreeMixin):"""用例树,管理用例,此表自我递归,继承TreeMixin的方法"""name = models.CharField(max_length=200, null=False, verbose_name='node名称')parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, related_name="children")pro = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="case_node", verbose_name="项目下节点")class Meta:managed=Truedb_table = 'auto_case_node'def __str__(self):return self.nameclass TestCase(BaseModel):"""测试用例"""name = models.CharField(max_length=100, verbose_name="用例名称")node = models.ForeignKey(Casenode, on_delete=models.DO_NOTHING, related_name="test_case", verbose_name="接口树管理用例")description = models.TextField(blank=True, null=True, verbose_name="用例描述")path = models.CharField(max_length=200, verbose_name="接口路径")method = models.CharField(max_length=10,choices=[("GET", "GET"), ("POST", "POST"), ("PUT", "PUT"), ("DELETE", "DELETE"), ("PATCH", "PATCH")],verbose_name="请求方法")headers = models.JSONField(blank=True, null=True, verbose_name="请求头")params = models.JSONField(blank=True, null=True, verbose_name="Query 参数")body = models.JSONField(blank=True, null=True, verbose_name="请求体")response = models.JSONField(blank=True, null=True, verbose_name='返回结果')api = models.ForeignKey(API, on_delete=models.DO_NOTHING, related_name="test_cases", verbose_name="关联接口")checkrestype = models.IntegerField(null=True, verbose_name='检查数据类型 0是返回头,1是返回数据,2是接口状态')checkmethod = models.CharField(max_length=50, null=True, verbose_name='返回检查方式')checkdata = models.CharField(max_length=200, null=True, verbose_name='检查期望')execsort = models.IntegerField(null=True, verbose_name='用例执行排序,在新增时通过获取三级节点下的数量自动生成')artificial = models.FloatField(null=True, verbose_name='人工执行用时')status = models.IntegerField(default=0, null=True, verbose_name='执行状态, 1执行中,2执行完成')class Meta:db_table = "auto_test_case"verbose_name = "测试用例"verbose_name_plural = "测试用例"indexes = [models.Index(fields=["name"]),]def __str__(self):return self.nameclass Casexkey(BaseModel):"""前置、后置执行"""case = models.ForeignKey(TestCase, on_delete=models.PROTECT, null=False, related_name="casex_key", verbose_name='用例的id,外键')beaft = models.IntegerField(null=True, verbose_name='前置或后置,0:前置,1:后置')method = models.CharField(max_length=200, null=False, verbose_name='执行关键字,执行时会映射到脚本 ')result = models.CharField(max_length=200, null=True, verbose_name='变量名称')pars = models.IntegerField(null=True, verbose_name='参数数量')params1 = models.TextField(null=True, verbose_name='参数1')params2 = models.TextField(null=True, verbose_name='参数2')params3 = models.TextField(null=True, verbose_name='参数3')params4 = models.TextField(null=True, verbose_name='参数4')params5 = models.TextField(null=True, verbose_name='参数5')params6 = models.TextField(null=True, verbose_name='参数6')type1 = models.CharField(max_length=10, null=True, verbose_name='参数一类型')type2 = models.CharField(max_length=10, null=True, verbose_name='参数二类型')type3 = models.CharField(max_length=10, null=True, verbose_name='参数三类型')type4 = models.CharField(max_length=10, null=True, verbose_name='参数四类型')type5 = models.CharField(max_length=10, null=True, verbose_name='参数五类型')type6 = models.CharField(max_length=10, null=True, verbose_name='参数六类型')class Meta:managed = Truedb_table = 'auto_casexec_key'def __str__(self):return '公共方法名称:%s\t' % (self.method)class TestSuite(BaseModel):"""测试套件:用例集合"""name = models.CharField(max_length=100, verbose_name="套件名称")description = models.TextField(blank=True, null=True, verbose_name="套件描述")test_cases = models.ManyToManyField(TestCase, related_name="suites", verbose_name="包含用例")name = models.CharField(max_length=100, verbose_name="套件名称")pro= models.ForeignKey(Project, null=True, on_delete=models.DO_NOTHING, related_name="test_suite")is_driven = models.IntegerField(default=0, null=True, verbose_name='数据驱动判断')filename = models.CharField(max_length=200, null=True, verbose_name='文件原名称')savename = models.CharField(max_length=200, null=True, verbose_name='文件存储名称')artificial = models.FloatField(null=True, verbose_name='人工执行时间')status = models.IntegerField(default=0, null=True, verbose_name='执行状态,0待执行,1执行中')class Meta:db_table = "auto_test_suite"verbose_name = "测试套件"verbose_name_plural = "测试套件"def __str__(self):return self.nameclass TestPlan(BaseModel):"""执行计划"""name = models.CharField(max_length=100, verbose_name="计划名称")environment = models.ForeignKey(Environment, on_delete=models.SET_NULL, null=True, related_name="test_plan", verbose_name="执行环境")description = models.TextField(blank=True, null=True, verbose_name="计划描述")suite = models.ForeignKey(TestSuite, on_delete=models.CASCADE, related_name="test_plan", verbose_name="关联套件")schedule = models.CharField(max_length=50, blank=True, null=True, verbose_name="定时任务表达式")qymsg = models.IntegerField(null=True, help_text='0,不发送消息, 1,发送消息')webhook = models.CharField(max_length=500, null=True, help_text='企业微信群机器人webhook')class Meta:db_table = "auto_test_plan"verbose_name = "执行计划"verbose_name_plural = "执行计划"def __str__(self):return self.nameclass Script(BaseModel):"""脚本(前置/后置、SQL/Python)"""kw_name = models.CharField(max_length=50, null=True, unique=True, verbose_name='脚本文件名称')script_type = models.CharField(max_length=20,choices=[("PYTHON", "Python Script"), ("SQL", "SQL Script")],verbose_name="脚本类型")methed_name = models.CharField(max_length=200, null=True, unique=True,verbose_name='脚本里面可以多个函数,取其中一个作入口函数名称,唯一')content = models.TextField(null=True, verbose_name='脚本内容 ')pars = models.IntegerField(null=True, verbose_name='参数数量')rules = models.TextField(null=True, verbose_name='规则描述,备注')public = models.IntegerField(default=0, verbose_name="以项目为维度,0:为私有,1:为公开")pro = models.ForeignKey(Project, null=True, on_delete=models.DO_NOTHING, related_name="script",)class Meta:db_table = "auto_script"verbose_name = "脚本"verbose_name_plural = "脚本"def __str__(self):return f"{self.kw_name} ({self.script_type})"class TestPlanResult(BaseModel):"""计划执行记录"""plan = models.ForeignKey(TestPlan, null=True, on_delete=models.DO_NOTHING, related_name="plan_result", verbose_name='执行组ID')tp_name = models.CharField(max_length=255, null=True, verbose_name='执行计划名称')pro = models.ForeignKey(Project, null=True, on_delete=models.DO_NOTHING, related_name="plan_result", verbose_name='项目ID')class Meta:managed=Truedb_table = 'auto_test_plan_result'def __str__(self):return '名称%s' % (str(self.tp_name))class TestSuiteResult(BaseModel):"""测试套件执行报告"""suite = models.ForeignKey(TestSuite, null=True, on_delete=models.DO_NOTHING, related_name="suites_result")excutnum = models.CharField(max_length=200, null=False, verbose_name='执行批次编号,按计划+用例生成数据,用此字段判断报告文件集,有多个相同编号的数据组成一封报告')planName = models.CharField(max_length=200, null=True, verbose_name='计划名称')cases = models.IntegerField(null=True, verbose_name='用例总数')passs = models.IntegerField(null=True, verbose_name='通过数量')fails = models.IntegerField(null=True, verbose_name='失败数量')totaltime = models.CharField(max_length=100, null=True, verbose_name='计划执行总用时')sCount = models.IntegerField(null=True, verbose_name='300ms<=s<700ms的数量')nCount = models.IntegerField(null=True, verbose_name='700ms<=s<1000ms的数量')cCount = models.IntegerField(null=True, verbose_name='1000ms<=s的数量')pro = models.ForeignKey(Project, null=True, on_delete=models.DO_NOTHING, verbose_name='项目id')tpr = models.ForeignKey(TestPlanResult, null=True, on_delete=models.DO_NOTHING, related_name="suites_result", verbose_name='套件的id')artificial = models.FloatField(null=True, verbose_name='计划执行时人工用时')savetime = models.FloatField(null=True, verbose_name='比人工省时')plancname = models.CharField(max_length=50, null=True, verbose_name='计划创建人名称')execuname = models.CharField(max_length=50, null=True, verbose_name='报告创建人名称')status = models.IntegerField(default=0, null=True, verbose_name='执行状态,0:执行完成 ,1:执行中')class Meta:managed=Truedb_table = 'auto_test_suite_result'def __str__(self):return '编号%s' % (str(self.excutnum))class TestResult(BaseModel):"""用例执行结果"""casename = models.CharField(max_length=100, null=True, verbose_name="存放用例名称")excutnum = models.CharField(max_length=200, null=False,verbose_name='执行批次编号,按计划+用例生成数据,用此字段判断报告文件集,有多个相同编号的数据组成一封报告')loopnum = models.CharField(max_length=200, null=True, verbose_name='执行循环的编号')test_plan = models.ForeignKey(TestPlan, null=True, on_delete=models.DO_NOTHING, related_name="case_result", verbose_name="关联执行计划,可为空,用例可单独执行")test_case = models.ForeignKey(TestCase, on_delete=models.DO_NOTHING, related_name="case_result", verbose_name="关联用例")status = models.CharField(max_length=20,choices=[("PASS", "Pass"), ("FAIL", "Fail")],verbose_name="执行结果")response_data = models.JSONField(blank=True, null=True, verbose_name="请求信息与响应数据,这里有数据性能瓶颈,大家遇到再自行解决")duration = models.FloatField(verbose_name="耗时(秒)")driven = models.IntegerField(null=True, default=0, verbose_name='是否数据驱动,0:不驱动, 1:数据驱动')parentid = models.IntegerField(null=True, default=-1, verbose_name='驱动第一条数据id')exectime = models.FloatField(null=True, verbose_name='用例执行用时')savetime = models.FloatField(null=True, verbose_name='比人工省时')class Meta:db_table = "auto_test_result"verbose_name = "测试结果"verbose_name_plural = "测试结果"indexes = [models.Index(fields=["status"]),]def __str__(self):return f"{self.test_case.name} - {self.status}"class BeaftResult(BaseModel):"""前置、后置执行结果"""id = models.AutoField(primary_key=True)casename = models.CharField(max_length=100, null=True, verbose_name="存放用例名称")status = models.IntegerField(null=False, verbose_name='执行结果状态 ,1是成功,0是失败')elapsedt = models.CharField(max_length=100, null=True, verbose_name='请求响应时间')qutoe_case_type = models.IntegerField(null=True, default=0, verbose_name='0前置,1后置')qutoe_case_execorder = models.IntegerField(default=0, null=True, verbose_name='自定义方法前后执行:0 前, 1 后')tr = models.ForeignKey(TestResult, null=True, on_delete=models.DO_NOTHING, related_name="beaft_result", verbose_name='用例测试报告外键')class Meta:managed = Truedb_table = 'auto_beaft_result'

5.2.3、生成表

models.py文件里面class 除了BaseModel外,其他的完成生成表操作后,都会在mysql中生成对应的表。

运行命令(老演员了):

python manage.py makemigrations  #根据在 models.py 中定义或修改的模型(Model),初始化用户表,没有新增models,这里运行不会改为任何模型,默认生成在应用目录下的 migrations/ 文件夹里
python manage.py migrate    #Django 会读取 migrations 文件,然后执行对应的 SQL 语句。将数据更新到数据库;

生成表的部分各位先自行操作,后续我会补上截图
因为我虚拟机出了一点小问题,安装的mysql8容器崩了,导致无法生成表,不想重装,先去研究如何解决,然后再将解决方案分享出来。

6、总结&预告

本章节将后端代码架构与数据库设计完成,开头最难的部分算是做完了,接下来便是开始编写代码,下一章会进行两个页面代码编写,项目管理与环境管理页面;顺便会将平台前端页面的菜单做出来。
所以下一章正式进行代码编写阶段,期待~

http://www.dtcms.com/a/411081.html

相关文章:

  • 深入解析:什么是矩阵系统源码搭建定制化开发,支持OEM贴牌
  • Nginx高并发原理与Tomcat实战全解析:从IO模型到HTTPS配置与故障排查(第七周)
  • 网站推广一般在哪个网做百度快照优化推广
  • STM32 外设驱动模块:Tracking 循迹模块
  • 新版发布!“零讯”微信小程序版本更新
  • 广西建设厅微信网站网站正在建设中的
  • 模板板网站wordpress前台登录插件
  • 河北网站制作报价网站优化公司服务
  • 人脸特征可视化进阶:用 dlib+OpenCV 绘制面部轮廓与器官凸包
  • display ip routing-table故障判断及题目
  • 晨控CK-GW04S与欧姆龙PLC配置Ethernet/IP通讯连接手册
  • 动态IP的特点
  • 团购网站推广怎么做微信公众号怎么创建要多少钱
  • CMDLET使用教程详解
  • 短视频流量|基于SprinBoot+vue的短视频流量数据分析系统(源码+数据库+文档)
  • 安装测试用例
  • ubuntu 网络监听工具及使用方法详解
  • 微信公众号网站自己做导航条WordPress在手机能更新
  • STM32 单片机开发 - FreeRTOS 实时操作系统
  • 网站如何续费深圳网上创建公司
  • UNet改进(41):基于PyTorch的轻量量化UNet
  • [vscode] Tab键无法缩进
  • 网站vr用什么做网站推广的技术有哪些
  • ubuntu24.04安装todesk远程工具
  • GPT-4 赋能恶意软件 GPT-MalPro:国内首现动态生成规避检测的勒索程序技术深度解析
  • ubuntu22.04安装cuda11.4版本
  • 网站建设与用户需求分析网络营销案例ppt课件
  • 八戒网站做推广婚庆策划公司加盟
  • 江苏建设行业证书编号查询网站男女性做那个视频网站
  • uniapp获取设备的IP地址(已踩坑,开箱即用)