- 一、用户登录功能
准备:
pip3 install djangorestframework
pip3 install djangorestframework-simplejwt
1、进入setting.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api_autotest_app', #注册app
'rest_framework.authtoken', #添加token模块
'rest_framework', #注册rest_framework
]
# REST_FRAMEWORK、simplejwt相关配置
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', # 使用JWT进行权限验证
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication', # 通过 JWT 进行用户授权,验证过程需要访问数据库
'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication', # 通过 JWT 的 Token 进行用户验证,验证过程不需要访问数据库
),
'DEFAULT_PAGINATION_CLASS': (
'rest_framework.pagination.PageNumberPagination',
),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', # 指定支持coreapi的Schema
}
AUTH_USER_MODEL = 'api_autotest_app.mUser'
# simplejwt 配置
JWT_SIGNING_KEY = '123456'
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=15),
'REFRESH_TOKEN_LIFETIME': timedelta(days=15),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': JWT_SIGNING_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(days=15),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=15),
}
2、重写User模块
models.py
from django.db import models
import hashlib
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _
# Create your models here.
class mUser(AbstractUser):
"""
自定义的用户模块
"""
# 微信同步的用户信息
openid = models.CharField(
verbose_name=_('钉钉OpenID'), help_text=_('钉钉OpenID'), max_length=100, unique=True, null=True, blank=True)
avatar_url = models.URLField(
verbose_name=_('头像'), help_text=_('头像'), null=True, blank=True)
nick_name = models.CharField(
verbose_name=_('昵称'), help_text=_('昵称'), max_length=100, null=True, blank=True, unique=True)
phone = models.CharField(
verbose_name=_('手机号'), help_text=_('手机号'), max_length=100, null=True, blank=True)
def create_username_password(self):
'''
自动通过openid创建用户名 username 和密码 password。
'''
if not self.username and not self.password and self.openid:
key = settings.SECRET_KEY
self.username = hashlib.pbkdf2_hmac(
"sha256", getattr(self, 'openid').encode(encoding='utf-8'), key.encode(encoding='utf-8'), 10).hex()
def save(self, *args, **kwargs):
self.create_username_password()
super().save(*args, **kwargs)
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_dMODEL'
3、实现用户登录功能
(1)、使用rest_framework模块的serializers序列化
api_autotest_app目录下新建serializers.py
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from .models import *
class JfwTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super(JfwTokenObtainPairSerializer, cls).get_token(user)
token['username'] = user.username
return token
(2)、重写rest_framework 接口返回格式
api_autotest_app->commom目录下新建api_response.py
from rest_framework.response import Response
from rest_framework.serializers import Serializer
class JsonResponse(Response):
"""
An HttpResponse that allows its data to be rendered into
arbitrary media types.
"""
def __init__(self, data=None, code=None, msg=None,
status=None,
template_name=None, headers=None,
exception=False, content_type=None):
"""
Alters the init arguments slightly.
For example, drop 'template_name', and instead use 'data'.
Setting 'renderer' and 'media_type' will typically be deferred,
For example being set automatically by the `APIView`.
"""
super().__init__(None, status=status)
if isinstance(data, Serializer):
msg = (
'You passed a Serializer instance as data, but '
'probably meant to pass serialized `.data` or '
'`.error`. representation.'
)
raise AssertionError(msg)
self.data = {"code": code, "msg": msg, "data": data}
self.template_name = template_name
self.exception = exception
self.content_type = content_type
if headers:
for name, value in headers.items():
self[name] = value
(3)、实现login接口
api_autotest_app->api目录下新建login.py
from rest_framework.views import APIView
from api_autotest_app.serializers import JfwTokenObtainPairSerializer
from api_autotest_app.common.api_response import JsonResponse
from django.contrib.auth import authenticate
class Login(APIView):
"""
post:
管理登录接口
"""
authentication_classes = []
permission_classes = []
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
if not username or not password:
return JsonResponse(code=999995, msg="参数有误")
user = authenticate(username=username, password=password)
if user and user.is_active and user.is_superuser:
token = JfwTokenObtainPairSerializer.get_token(user).access_token
data = {
'access_token': str(token)
}
return JsonResponse(data=data, code=0, msg="成功!")
else:
return JsonResponse(code=99995, msg="账号或密码错误!")
(4)、配置路由
api_autotest_app目录新建urls.py
from django.conf.urls import url
from api_autotest_app.api import login
urlpatterns = [
url(r'^user/login$', login.Login.as_view()),
]
api_autotest_admin->urls.py
"""api_autotest_admin URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.urls import path, include
from api_autotest_app import urls
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^api/', include(urls)),
]
创建管理员:
python3 manage.py createsuperuser
启动项目:
python3 manage.py runserver 8005
(5)、实现登录页面
克隆项目
git clone https://github.com/PanJiaChen/vue-admin-template.git
进入根目录:
npm install
基础依赖包添加成功后执行
npm run dev
启动成功后可以看到进入登录页面
- 对接登录功能
修改文件将mock改为我们自己的后端接口
配置代理:
修改接口:
src -> api->user.js
import request from '@/utils/request'
export function login(data) {
return request({
url: '/api/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/api/internal/admin/getUser',
method: 'get',
params: { }
})
}
src->utils->request.js
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 0) {
Message({
message: res.msg || 'Error',
type: 'error',
duration: 5 * 1000
})
登录页面
src->views->login-index.vue 去掉一些不要的东西
v的接口自动化测试平台
登录
使用管理员账号登录成功后进入首页
- 实现项目模块
编写后台接口
1、创建project表 model.py
class Project(models.Model):
"""
项目表
"""
ProjectType = (
('prd', '生产'),
('test', '测试')
)
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50, verbose_name='项目名称')
version = models.CharField(max_length=50, verbose_name='版本')
type = models.CharField(max_length=50, verbose_name='类型', choices=ProjectType)
description = models.CharField(max_length=1024, blank=True, null=True, verbose_name='描述')
status = models.BooleanField(default=True, verbose_name='状态')
LastUpdateTime = models.DateTimeField(auto_now=True, verbose_name='最近修改时间')
createTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
user = models.ForeignKey(mUser, on_delete=models.SET_NULL, null=True, max_length=1024, verbose_name='创建人')
def __unicode__(self):
return self.name
def __str__(self):
return self.name
class Meta:
verbose_name = '项目'
verbose_name_plural = '项目'
2、序列化信息
class ProjectDeserializer(serializers.ModelSerializer):
"""
项目信息反序列化
"""
class Meta:
model = Project
fields = "__all__"
class ProjectSerializer(serializers.ModelSerializer):
"""
项目信息序列化
"""
LastUpdateTime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
createTime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
user = serializers.CharField(source='user.username')
class Meta:
model = Project
fields = "__all__"
3、接口实现
class ProjectList(APIView):
def get(self, request):
"""
获取项目列表
:param request:
:return:
"""
try:
page_size = int(request.GET.get("page_size", 20)) #每页20条
page = int(request.GET.get("page", 1)) # 默认从第一页开始
except (TypeError, ValueError):
return JsonResponse(code=999995, msg="page字段和page_size字段 必须为整数!")
param = {}
name = request.GET.get("name")
status = request.GET.get("status")
if name:
param['name'] = name
if status:
param['status'] = True if status=="true" else False
if param:
obi = Project.objects.filter(**param).order_by("id")
else:
obi = Project.objects.all().order_by("id")
paginator = Paginator(obi, page_size)
total = paginator.num_pages
try:
obm = paginator.page(page)
except PageNotAnInteger:
obm = paginator.page(1)
except EmptyPage:
obm = []
serialize = ProjectSerializer(obm, many=True)
return JsonResponse(data={"data": serialize.data,
"page": page,
"total": total
}, code=Code.SUCCESS, msg="成功")
class AddProject(APIView):
def parameter_check(self, data):
"""
验证参数
:param data:
:return:
"""
try:
# 必传参数 name, version, type
if not data["name"] or not data["version"] or not data["type"]:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
if data["type"] not in ["pro", "test"]:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
except KeyError:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
def post(self, request):
"""
新增项目
:param request:
:return:
"""
data = JSONParser().parse(request)
result = self.parameter_check(data)
if result:
return result
data["user"] = request.user.pk
project_serializer = ProjectDeserializer(data=data)
try:
Project.objects.get(name=data["name"])
return JsonResponse(code=Code.DATA_HAS_EXISTED, msg="存在相同名称")
except ObjectDoesNotExist:
if project_serializer.is_valid():
project_serializer.save()
return JsonResponse(data={
"project_id": project_serializer.data.get("id")
}, code=Code.SUCCESS, msg="成功")
else:
return JsonResponse(code=Code.ERROR, msg="失败")
class UpdateProject(APIView):
def parameter_check(self, data):
"""
校验参数
:param data:
:return:
"""
try:
# 校验project_id类型为int
if not isinstance(data["id"], int):
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
# 必传参数 name, version , type
if not data["name"] or not data["version"] or not data["type"]:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
# type 必为pro, test
if data["type"] not in ["pro", "test"]:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
except KeyError:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
def post(self, request):
"""
修改项目
:param request:
:return:
"""
data = JSONParser().parse(request)
result = self.parameter_check(data)
if result:
return result
del data['user']
# 查找项目是否存在
try:
obj = Project.objects.get(id=data["id"])
if not request.user.is_superuser and obj.user.is_superuser:
return JsonResponse(code=Code.USER_NOT_PERMISSION, msg="无操作权限!")
except ObjectDoesNotExist:
return JsonResponse(code=Code.DATA_NOT_EXISTED, msg="项目不存在!")
# 查找是否相同名称的项目
pro_name = Project.objects.filter(name=data["name"]).exclude(id=data["id"])
if len(pro_name):
return JsonResponse(code=Code.DATA_HAS_EXISTED, msg="存在相同名称")
else:
serializer = ProjectDeserializer(data=data)
with transaction.atomic():
if serializer.is_valid(raise_exception=True):
# 修改项目
serializer.update(instance=obj, validated_data=data)
return JsonResponse(code=Code.SUCCESS, msg="成功")
else:
return JsonResponse(code=Code.ERROR, msg="失败")
class DelProject(APIView):
def parameter_check(self, data):
"""
校验参数
:param data:
:return:
"""
try:
if not isinstance(data["ids"], list):
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
for i in data["ids"]:
if not isinstance(i, int):
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
except KeyError:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
def post(self, request):
"""
删除项目
:param request:
:return:
"""
data = JSONParser().parse(request)
result = self.parameter_check(data)
if result:
return result
try:
for i in data["ids"]:
try:
obj = Project.objects.get(id=i)
if not request.user.is_superuser and obj.user.is_superuser:
return JsonResponse(code=Code.USER_NOT_PERMISSION, msg=str(obj)+"无操作权限!")
except ObjectDoesNotExist:
return JsonResponse(code=Code.DATA_NOT_EXISTED, msg="项目不存在!")
for j in data["ids"]:
obj = Project.objects.filter(id=j)
obj.delete()
return JsonResponse(code=Code.SUCCESS, msg="成功")
except ObjectDoesNotExist:
return JsonResponse(code=Code.DATA_NOT_EXISTED, msg="项目不存在!")
class DisableProject(APIView):
def parameter_check(self, data):
"""
校验参数
:param data:
:return:
"""
try:
# 校验project_id类型为int
if not isinstance(data["id"], int):
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
except KeyError:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
def post(self, request):
"""
禁用项目
:param request:
:return:
"""
data = JSONParser().parse(request)
result = self.parameter_check(data)
if result:
return result
try:
obj = Project.objects.get(id=data["id"])
if not request.user.is_superuser and obj.user.is_superuser:
return JsonResponse(code=Code.USER_NOT_PERMISSION, msg=str(obj) + "无操作权限!")
obj.status = False
obj.save()
return JsonResponse(code=Code.SUCCESS, msg="成功")
except ObjectDoesNotExist:
return JsonResponse(code=Code.DATA_NOT_EXISTED, msg="项目不存在!")
class EnableProject(APIView):
def parameter_check(self, data):
"""
校验参数
:param data:
:return:
"""
try:
if not isinstance(data["id"], int):
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
except KeyError:
return JsonResponse(code=Code.PARAM_IS_INVALID, msg="参数有误!")
def post(self, request):
"""
启用项目
:param request:
:return:
"""
data = JSONParser().parse(request)
result = self.parameter_check(data)
if result:
return result
# 查找项目是否存在
try:
obj = Project.objects.get(id=data["id"])
if not request.user.is_superuser and obj.user.is_superuser:
return JsonResponse(code=Code.USER_NOT_PERMISSION, msg=str(obj) + "无操作权限!")
obj.status = True
obj.save()
return JsonResponse(code=Code.SUCCESS, msg="成功")
except ObjectDoesNotExist:
return JsonResponse(code=Code.DATA_NOT_EXISTED, msg="项目不存在!")
4、配置接口路由
- 实现前端页面
dashoard->index
查询
添加
{{ row.id }}
{{ row.name }}
测试环境
生产环境
{{row.user}}
{{row.description}}
{{ row.createTime }}
{{ row.LastUpdateTime }}
已禁用
已启动
编辑
启动
禁用
删除
具体一些配置就不一一说明了
实现项目详情页面