Django 接口自动化测试平台实现(一)
0. 引言
0.1 平台功能概述
本接口自动化测试平台的整体功能如下图所示:
0.2 创建项目与应用
本项目环境如下:
- python 3.6.5
- pip install django==2.2.4
- pip install redis==2.10.6
- pip install eventlet==0.25.2
- pip install celery==3.1.26.post2
对于 Django 的基础使用教程,可以参考之前的Diango文章
1)创建本项目工程
# 方式一 django-admin startproject InterfaceAutoTest# 方式二 python -m django startproject interface_test_platform
此时工程结构如下所示:
2)创建应用
在项目目录下,使用如下命令创建应用:
django-admin startapp interfacetestplatform
此时工程结构目录如下:
3)注册应用
在项目目录 InterfaceAutoTest/settings.py 中,找到 INSTALLED_APPS 配置项,在列表末尾添加新建的应用名称“interfacetestplatform”:
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','interfacetestplatform,' ]
新建的应用需要在 INSTALLED_APPS 配置项中注册,Django 会根据该配置项到应用下查找模板等信息。
4)使用 Bootstrap
Bootstrap 是流行的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 Web 项目。
- 下载 bootstrap:起步 · Bootstrap v3 中文文档 | Bootstrap 中文网
- 下载 jquery:Download jQuery | jQuery
在项目目录下新建一个 static 目录,将解压后的如 bootstrap-3.3.7-dist 目录整体拷贝到 static 目录中,并将文件名改为 bootstrap。
由于 bootstrap 依赖 jQuery,我们需要提前下载并引入 jQuery。在 static 目录下,新建 css 和 js 目录,作为后面的样式文件和 js 文件的存放地,将我们的 jQuery 文件拷贝到 static/js/ 目录下。
ECharts 是一个使用 JavaScript 实现的开源可视化库,在本项目中用于用例/集合的执行结果统计可视化。于是我们引入 echarts 文件到 static/js/ 目录下。
此时 static 目录结构如下图所示:
在项目目录下的 settings.py 文件的末尾添加如下配置,用于指定静态文件的搜索目录:
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]
通过 STATICFILES_DIRS 属性,可以指定静态资源的路径,此处配置的是项目根目录下的 static 文件夹下。
默认情况下,Django 只能识别项目应用目录下的 static 目录的静态资源,不会识别到项目目录下的 static目录,因此通过 STATICFILES_DIR 属性可以解决这个问题。
5)创建应用的模板目录
在应用目录下新建一个 templates 目录,专门存放本应用所有的模板文件。
默认情况下,Django 只能识别项目应用目录下的 templates 目录的静态资源。本工程因仅涉及一个应用,因此选用此方案。
若应用较多,为了易于维护,可将各应用的模板文件进行统一处理,则在项目目录下新建 templates 目录,并在 settings.py 中新增配置:
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR, 'templates')],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},}, ]
6)启动 Django 的 Web 服务
在项目目录下,运行如下命令启动端口号为 8000 的 Django 的 Web 服务:
python manage.py runsever 8000 # 端口号可自定义,不写则默认8000
启动日志如下:
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. Run 'python manage.py migrate' to apply them. July 13, 2021 - 10:03:23 Django version 3.2.5, using settings 'InterfaceAutoTest.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.
启动成功后,用浏览器访问 127.0.0.1:8000,可以看到 Django 默认的页面,如下所示即代表服务启动成功:
7)配置 Mysql 数据库
修改项目目录下的 settings.py 文件,将 DATABASES 配置项改为如下配置:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'interface_platform', # 已存在的库名'USER': 'root', # 数据库账号'PASSWORD': '123', # 数据库密码'HOST': '127.0.0.1', # 数据库IP'PORT': '3306', # 数据库端口} }
若使用的是 Python 3 的 pymysql,则需要在项目的 __init__.py 文件中添加如下内容,避免报错:
import pymysql pymysql.version_info = (1, 4, 13, "final", 0) # 指定版本。在出现“mysqlclient 1.4.0 or newer is required; you have 0.9.3.”报错时加上此行 pymysql.install_as_MySQLdb()
8)创建 Admin 站点超级用户
首先在项目目录下进行数据迁移,生成 auth_user 等基础表:
python manage.py migrate
在工程目录下,执行以下命令创建超级用户,用于登录 Django 的 Admin 站点:
D:\InterfaceAutoTest>python manage.py createsuperuser Username (leave blank to use 'administrator'): admin # 用户名 Email address: admin@123.com # 符合邮箱格式即可 Password: # 密码 Password (again): # 二次确认密码 The password is too similar to the username. This password is too common. Bypass password validation and create user anyway? [y/N]: y Superuser created successfully.
创建好 superuser 后,访问 127.0.0.1:8000/admin,用注册的 admin 账户进行登录(数据参考的就是 auth_user 表,并且必须是管理员用户才能进入)。
配置 admin 语言和时区
登录 admin 页面,可以看到页面的标题、菜单显示的语言是英文,那么如何展示为中文呢?
在 settings.py 中,找到 MIDDLEWARE 属性,添加中间件。
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.locale.LocaleMiddleware', 'django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware', ]
同时,在后续添加项目信息表数据时,可以发现数据的创建时间、更新时间字段的时间不是本地时间,而是 UTC 时间,那么怎么展示为国内本地时间呢?
也是 settings.py 中,修改 TIME_ZONE 和 USE_TZ 的配置项:
TIME_ZONE = 'Asia/Shanghai'USE_TZ = False
这样配置后,admin 页面中数据表的时间字段以及前端模板中的时间字段都是本地时区的时间。
- 当 USE_TZ 为 False 时,TIME_ZONE值是 Django 存储所有日期时间的时区。
- 当 USE_TZ 为 True 时,TIME_ZONE值是 Django 在模板中显示日期时间和解释表单中输入的日期时间的默认时区。简单起见,USE_TZ 直接设为 False。
1. 登录功能
预期效果如下:
1.1 定义路由
1) 路由定义规则说明
路由的基本信息包含路由地址和视图函数,路由地址即访问网址,视图函数即客户端在访问指定网址后,服务器端所对应的处理逻辑。
在应用目录(interfacetestplatform 目录)下新建 urls.py,将所有属于该应用的路由都写入该文件中,这样更容易管理和区分每个应用的路由地址,而项目目录(InterfaceAutoTest)下的 urls.py 是将每个应用的 urls.py 进行统一管理。
这种路由设计模式是 Django 常用的,其工作原理如下:
- 运行 InterfaceAutoTest 项目时,Django 从 interfacetestplatform (应用)目录的 urls.py 找到对应应用所定义的路由信息,生成完整的路由表。
- 当用户在浏览器上访问某个路由地址时,Django 服务端就会收到该用户的请求信息。Django 从当前请求信息获取路由地址,首先匹配项目目录下的 urls.py 的路由列表。转发到指定应用的 urls.py 的路由列表。
- 再执行应用下的路由信息所指向的视图函数,从而完成整个请求响应过程。
2)路由配置
配置项目 urls.py:InterfaceAutoTest/urls.py
from django.contrib import admin from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls), # 指向内置Admin后台系统的路由文件sites.pypath('', include('interfacetestplatform.urls')), # 指向interfacetestplatform应用的urls.py]
由于默认地址分发给了 interfacetestplatform(应用)的 urls.py 进行处理,因此需要对 interfacetestplatform/urls.py 编写路由信息,代码如下:
from django.urls import path from . import viewsurlpatterns = [path('', views.index),path('login/', views.login),path('logout/', views.logout), ]
如路由信息 path('', views.index) 的 views.index 是指专门处理网站默认页的用户请求和响应过程的视图函数名称 index,其他路由规则原理一样。
1.2 定义视图函数
1)定义 Form 表单类
在定义视图函数之前,我们先定义 Django 提供的表单模型类,来代替原生的前端 Form 表单。
在应用目录下,新建 form.py:
1 from django import forms 2 3 4 class UserForm(forms.Form): 5 username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'})) 6 password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
2)定义视图函数
在应用的 interfacepestplatform/views.py (视图模块)中添加如下代码:
1 from django.shortcuts import render, redirect2 from django.contrib import auth # Django用户认证(Auth)组件一般用在用户的登录注册上,用于判断当前的用户是否合法3 from django.contrib.auth.decorators import login_required4 from .form import UserForm5 import traceback6 7 8 # Create your views here.9 # 默认页的视图函数 10 @login_required 11 def index(request): 12 return render(request, 'index.html') 13 14 15 # 登录页的视图函数 16 def login(request): 17 print("request.session.items(): {}".format(request.session.items())) # 打印session信息 18 if request.session.get('is_login', None): 19 return redirect('/') 20 # 如果是表单提交行为,则进行登录校验 21 if request.method == "POST": 22 login_form = UserForm(request.POST) 23 message = "请检查填写的内容!" 24 if login_form.is_valid(): 25 username = login_form.cleaned_data['username'] 26 password = login_form.cleaned_data['password'] 27 try: 28 # 使用django提供的身份验证功能 29 user = auth.authenticate(username=username, password=password) # 从auth_user表中匹配信息,匹配成功则返回用户对象;反之返回None 30 if user is not None: 31 print("用户【%s】登录成功" % username) 32 auth.login(request, user) 33 request.session['is_login'] = True 34 # 登录成功,跳转主页 35 return redirect('/') 36 else: 37 message = "用户名不存在或者密码不正确!" 38 except: 39 traceback.print_exc() 40 message = "登录程序出现异常" 41 # 用户名或密码为空,返回登录页和错误提示信息 42 else: 43 return render(request, 'login.html', locals()) 44 # 不是表单提交,代表只是访问登录页 45 else: 46 login_form = UserForm() 47 return render(request, 'login.html', locals()) 48 49 50 # 注册页的视图函数 51 def register(request): 52 return render(request, 'register.html') 53 54 55 # 登出的视图函数:重定向至login视图函数 56 @login_required 57 def logout(request): 58 auth.logout(request) 59 request.session.flush() 60 return redirect("/login/")
render 方法
用来生成网页内容并返回给客户端,其两个必须参数表示:第一个参数是浏览器想服务器发送的请求对象;第二个参数是模板名称,用于生成网页内容。
auth 模块
auth 模块是 cookie 和 session 的升级版。
auth 模块是对登录认证方法的一种封装,之前我们获取用户输入的用户名及密码后需要自己从 user 表里查询有没有用户名和密码符合的对象,而有了 auth 模块之后就可以很轻松地去验证用户的登录信息是否存在于数据库(auth_user 表)中。
除此之外,auth 还对 session 做了一些封装,方便我们校验用户是否已登录。
login 方法
对于非 POST 方法的请求(如 GET 请求),直接返回空的表单,让用户可以填入数据。
对于 POST 方法请求,接收表单数据,并验证:
- 使用表单类自带的 is_valid() 方法进一步完成数据验证工作;
- 验证成功后可以从表单对象的 cleand_data 数据字典中获取表单的具体值;
- 如果验证不通过,则返回一个包含先前数据的表单给前端页面,方便用户修改。也就是说,它会帮你保留先前填写的数据内容,而不是返回一个空表。
- 另外,这里使用了一个小技巧,python 内置了一个 locals() 函数,它返回当前所有的本地变量字典,我们可以偷懒的将这作为 render 函数的数据字典参数值,就不用费劲去构造一个形如 {'message':message, 'login_form':login_form} 的字典了。这样做的好处是大大方便了我们;但同时也可能往模板传入一些多余的变量数据,造成数据冗余降低效率。
@login_required
为函数增加装饰器 @login_required,这种方式可以实现未登录禁止访问首页的功能。
此种方式需要在项目 settings.py 中添加如下配置:
LOGIN_URL = '/login/'
通过 LOGIN_URL 告诉 Django 在用户没登录的情况下,重定向的登录地址;如果没配置该属性,Django 会重定向到默认地址。
如果不用装饰器方式,也可以在函数内部判断用户状态,并实现重定向。如下所示,效果是一样的:
def index(request):print("request.user.is_authenticated: {}".format(request.user.is_authenticated))if not request.user.is_authenticated:return redirect("/login/")return render(request,'index.html')