Django_CMDB系统开发
一、CMDB相关概念
1、概念介绍
CMDB(配置管理数据库)存储与管理企业IT架构中设备的各种配置信息,它与所有服务支持和服务交付流程都紧密相联,支持这些流程的运转、发挥配置信息的价值,同时依赖于相关流程保证数据的准确性。
服务器集群或者分布式服务器 几十台、上百台,服务器相关数据信息,管理不方便。通过资产管理的方式,通过CMDB系统实现。
github一些开源的cmdb系统:https://github.com/search?q=cmdb
2、需求分析
本次开发的CMDB系统实现以下模块:
--用户管理模块
--用户组管理模块
--权限管理模块
--资产主机模块
--资产机房模块
--资产用户模块
概括一下,本次学习开发的CMDB,是一个收集服务器信息,实现服务器信息可视化,给自动化运维监控提供数据统计和展示等基础服务。
3、设计实现
CMDB使用关系图示:
本次开发的CMDB系统结构图示:
二、创建CMDB项目
1、创建项目
1、使用Pycharm创建Django项目
2、默认初始化配置
配置静态资源目录
创建static文件夹
时区配置
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False
settings.py配置
STATIC_URL = 'static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
# BASE_DIR / 'static'
BASE_DIR / 'static'
]
3、数据库配置
创建数据库
CREATE DATABASE cmdb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
配置数据库
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cmdb',
'USER': 'root',
'PASSWORD': 'fxx123',
'HOST': '10.0.0.131',
'PORT': '3306',
'OPTIONS': {
"init_command": "SET sql_mode='STRICT_TRANS_TABLES'"
}
}
}
__init__.py
import pymysql
pymysql.install_as_MySQLdb()
迁移数据库
python manage.py makemigrations # 生成迁移表
python manage.py migrate # 进行数据迁移
三、管理后台布局
1、后台前端模板介绍
使用INSPINIA模板,实现管理后台的前端模板页面
2、基础页面布局
先定义一个基础页面,包含各个页面中的公共部分,方便其他页面继承。
部署静态资源
在应用下建立模板目录,方便之后分开管理
定义路由
cmdb\cmdb\urls.py
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('dashboard/',include('dashboard.urls'))
]
cmdb\dashboard\urls.py
from django.urls import path
from dashboard.views import *
urlpatterns = [
path('base/',BaseView.as_view())
]
类视图
from django.shortcuts import render
from django.views.generic import View
class BaseView(View):
def get(self,request):
return render(request,'base.html')
模板页面
可以通过模板页面,进行修改。或者直接使用修改好的模板
注意静态资源路径的修改和替换
base.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB管理系统</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/plugins/sweetalert/sweetalert.css">
{% block load_css %}
{% endblock %}
</head>
<body>
<div id="wrapper">
<nav class="navbar-default navbar-static-side" role="navigation">
<div class="sidebar-collapse">
<ul class="nav metismenu" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element" >
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">{{ request.user.username }}</strong>
</span> <span class="text-muted text-xs block">{{ request.user.groups.filter.0 }}<b class="caret"></b></span> </span>
</a>
<ul class="dropdown-menu animated fadeInRight m-t-xs">
<li><a href="profile.html">个人信息</a></li>
</ul>
</div>
</li>
<li>
<a href="../dashboard/templates/index.html"><i class="fa fa-th-large"></i> <span class="nav-label">系统管理</span> <span
class="fa arrow"></span></a>
</li>
<li>
<a href="#"><i class="fa fa-bar-chart-o"></i> <span class="nav-label">资产管理</span><span
class="fa arrow"></span></a>
</li>
</ul>
</div>
</nav>
<div id="page-wrapper" class="gray-bg">
<div class="row border-bottom">
<nav class="navbar navbar-static-top " role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="#"><i class="fa fa-bars"></i>
</a>
</div>
<ul class="nav navbar-top-links navbar-right">
<li>
<span class="m-r-sm text-muted welcome-message">欢迎来到配置数据库管理系统 </span> </欢迎来到SYSCMDB自动化管理系统></span>
</li>
</ul>
</nav>
</div>
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>仪表盘</h2>
<ol class="breadcrumb">
<li>
<a href="../dashboard/templates/index.html">首页</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<h1>这是BASE页面</h1>
{% endblock %}
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/static/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<!-- Custom and plugin javascript -->
<script src="/static/js/inspinia.js"></script>
<script src="/static/js/plugins/pace/pace.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
function aaa(i){
console.log(i)
}
</script>
{% block load_js %}
{% endblock %}
</body>
</html>
查看效果
http://127.0.0.1:8000/dashboard/base/
以上页面视图和页面,作为测试使用。
3、首页面实现
路由
cmdb/urls.py
RediretView 重定向 URL跳转
from django.contrib import admin
from django.urls import path,include
from django.views.generic import RedirectView
urlpatterns = [
path('admin/', admin.site.urls),
path('',RedirectView.as_view(url='dashboard/')),
path('dashboard/',include('dashboard.urls'))
]
dashboard/urls.py
from django.urls import path
from dashboard.views import *
urlpatterns = [
path('base/',BaseView.as_view()),
path('',IndexView.as_view(),name='index'),
]
视图
dashboard/views.py
from django.shortcuts import render
from django.views.generic import View
class BaseView(View):
def get(self,request):
return render(request,'base.html')
# Create your views here.
class IndexView(View):
def get(self,request):
return render(request,'index.html')
模板
dashboard/templates/index.html
{% extends 'base.html' %}
{% block body%}
这是CMDB首页面
{% endblock %}
修改base.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB管理系统</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/plugins/sweetalert/sweetalert.css">
{% block load_css %}
{% endblock %}
</head>
<body>
<div id="wrapper">
<nav class="navbar-default navbar-static-side" role="navigation">
<div class="sidebar-collapse">
<ul class="nav metismenu" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element" >
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">{{ request.user.username }}</strong>
</span> <span class="text-muted text-xs block">{{ request.user.groups.filter.0 }}<b class="caret"></b></span> </span>
</a>
<ul class="dropdown-menu animated fadeInRight m-t-xs">
<li><a href="profile.html">个人信息</a></li>
</ul>
</div>
</li>
<li>
<a href="{% url 'index' %}"><i class="fa fa-bar-chart-o"></i> <span class="nav-label">首页</span></a>
</li>
<li>
<a href="../dashboard/templates/index.html"><i class="fa fa-th-large"></i> <span class="nav-label">系统管理</span> <span
class="fa arrow"></span></a>
</li>
<li>
<a href="#"><i class="fa fa-bar-chart-o"></i> <span class="nav-label">资产管理</span><span
class="fa arrow"></span></a>
</li>
</ul>
</div>
</nav>
<div id="page-wrapper" class="gray-bg">
<div class="row border-bottom">
<nav class="navbar navbar-static-top " role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="#"><i class="fa fa-bars"></i>
</a>
</div>
<ul class="nav navbar-top-links navbar-right">
<li>
<span class="m-r-sm text-muted welcome-message">欢迎来到配置数据库管理系统 </span> </欢迎来到SYSCMDB自动化管理系统></span>
</li>
</ul>
</nav>
</div>
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>仪表盘</h2>
<ol class="breadcrumb">
<li>
<a href="../dashboard/templates/index.html">首页</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<h1>这是BASE页面</h1>
{% endblock %}
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/static/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<!-- Custom and plugin javascript -->
<script src="/static/js/inspinia.js"></script>
<script src="/static/js/plugins/pace/pace.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
function aaa(i){
console.log(i)
}
</script>
{% block load_js %}
{% endblock %}
</body>
</html>
查看效果
4、高级视图类之TemplateView
TemplateView,这个类封装了View提供了更强大的功能。
使用TemplateView,加载渲染页面
使用TemplateView
dashboard/views.py
from django.shortcuts import render
from django.views.generic import View, TemplateView
class BaseView(View):
def get(self,request):
return render(request,'base.html')
# Create your views here.
# class IndexView(View):
# def get(self,request):
# return render(request,'index.html')
class IndexView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
在模板中调用
index.html
{% extends 'base.html' %}
{% block body%}
这是CMDB首页面
<p> {{ name }} </p>
{% endblock %}
查看显示效果
四、登录管理
1、登录基本实现
实现完成首页面后,为了能够更加安全,就需要实现一个登录功能,只有登录之后,才能够查看管理后台。
登录页面实现后的效果:
①路由
cmdb/urls.py
from django.contrib import admin
from django.urls import path,include
from django.views.generic import RedirectView
from dashboard.views import *
urlpatterns = [
path('admin/', admin.site.urls),
path('',RedirectView.as_view(url='dashboard/')),
path('login/',LoginView.as_view(),name='login'),
path('dashboard/',include('dashboard.urls'))
]
视图
dashboard/views.py
from django.shortcuts import render
from django.views.generic import View, TemplateView
class BaseView(View):
def get(self,request):
return render(request,'base.html')
# Create your views here.
# class IndexView(View):
# def get(self,request):
# return render(request,'index.html')
class IndexView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
class LoginView(TemplateView):
template_name = 'login.html'
在后端接收用户传输的数据
登录基础原理:前端页面输入账号密码===》后端接收信息参数 ===》类视图判断校验
模板页面通过ajax post请求发送数据
dashboard/templates/login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB系统 | 登录</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link href="/static/css/plugins/sweetalert/sweetalert.css" rel="stylesheet">
</head>
<body class="gray-bg">
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<div>
<h1 class="logo-name">CMDB</h1>
</div>
<h3>欢迎登录CMDB系统</h3>
<p>
</p>
<p>快乐游戏,欢乐至上</p>
<form class="m-t" id="login_form">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="用户名" name="username">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="密码" name="password">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">登录</button>
</form>
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
$('#login_form').submit( function () {
var str = $('#login_form').serialize();
$.post('{% url 'login' %}', str, function (res) {
if (res.status == 0) {
alert('登录成功')
} else {
alert('登录失败')
}
}
)
})
</script>
</body>
</html>
后端视图
校验账号和密码并返回数据
Tip:使用返回json数据格式的声明
from django.shortcuts import render
from django.views.generic import View, TemplateView
from django.http import JsonResponse
class BaseView(View):
def get(self,request):
return render(request,'base.html')
# Create your views here.
# class IndexView(View):
# def get(self,request):
# return render(request,'index.html')
class IndexView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
class LoginView(TemplateView):
template_name = 'login.html'
def post(self, request):
data = request.POST
# 校验用户和密码
if data.get('username') == 'admin' and data.get('password') == '123456':
res = {'status': 0, 'msg': '校验成功'}
else:
res = {'status': 1, 'msg': '用户名或者密码错误'}
return JsonResponse(res)
显示效果
美化提示窗口
模板引入sweetaltert js库
实现方式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB系统 | 登录</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link href="/static/css/plugins/sweetalert/sweetalert.css" rel="stylesheet">
</head>
<body class="gray-bg">
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<div>
<h1 class="logo-name">CMDB</h1>
</div>
<h3>欢迎登录CMDB系统</h3>
<p>
</p>
<p>快乐游戏,欢乐至上</p>
<form class="m-t" id="login_form">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="用户名" name="username">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="密码" name="password">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">登录</button>
</form>
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
$('#login_form').submit( function () {
var str = $('#login_form').serialize();
$.post('{% url 'login' %}', str, function (res) {
if (res.status == 0) {
alert('登录成功')
} else {
swal({
title: '登录失败',
type: 'error',
confirmButtonText: '知道了'
});
}
}
)
});
</script>
</body>
</html>
s表单验证 jquery.validate
引入js文件, jquery.validate 是基于jquery的,所有需要先引入jquery
校验代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB系统 | 登录</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link href="/static/css/plugins/sweetalert/sweetalert.css" rel="stylesheet">
</head>
<body class="gray-bg">
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<div>
<h1 class="logo-name">CMDB</h1>
</div>
<h3>欢迎登录CMDB系统</h3>
<p>
</p>
<p>快乐游戏,欢乐至上</p>
<form class="m-t" id="login_form">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="用户名" name="username">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="密码" name="password">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">登录</button>
</form>
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
$(document).ready(function () {
$("#login_form").validate({
rules: {
username: {
required: true,
minlength: 4
},
password: {
required: true,
minlength: 6
}
},
submitHandler: function () {
var str = $('#login_form').serialize();
$.post('{% url 'login' %}', str, function (res) {
console.log(res)
if ( res.status == 0) {
location.href = {% url 'index' %}
} else {
swal({
title: res.msg,
type: 'error',
confirmButtonText: "知道了"
});
}
});
}
});
});
</script>
</body>
</html>
2、Django的用户系统实现登录
以上操作,只是实现了登录的基本校验操作,但是没有用户信息,所有实际是不能够使用。
在Django中,提供了整个一套的登录相关方法,可以直接导入调用即可。
from django.contrib.auth import login, logout, authenticate
authenticate():就是用来验证用户的账号密码,如果验证成功就会返回一个User对象,如果失败就会返回None。
login():用来真正执行登录的函数,这里也会生成session存储进数据库。
logout():用来注销用户的。
实现登录功能
视图
dashboard/views.py
from django.shortcuts import render
from django.views.generic import View, TemplateView
from django.http import JsonResponse
from django.contrib.auth import login, logout, authenticate
class BaseView(View):
def get(self,request):
return render(request,'base.html')
class IndexView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
class LoginView(TemplateView):
template_name = 'login.html'
def post(self, request):
data = {}
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
data['status'] = 0
data['msg'] = "登陆成功"
else:
data['status'] = 1
data['msg'] = "账户或密码错误"
return JsonResponse(data)
模板
使用manager.py创建用户
注意在创建用户密码的时候,不要太弱,和用户名称邮箱雷同,认为不安全
python manage.py createsuperuser
user admin
email admin@qq.com
password fxx123
(cmdb) PS E:\cmdb> python manage.py createsuperuser
用户名 (leave blank to use '86199'): admin
电子邮件地址: admin@qq.com
Password:
Password (again):
密码长度太短。密码必须包含至少 8 个字符。
Bypass password validation and create user anyway? [y/N]: y 是否绕过密码验证并创建用户?
Superuser created successfully.
3、URL拦截器
虽然已经实现了登录系统功能,但是发现即使不通过登录系统,也可以直接通过URL访问管理后台的首页。所以,还需要在首页面上进行登录验证。登录允许访问,没有登录不允许访问。
防止通过URL直接访问 防翻墙
Django中提供了验证方法:
from django.contrib.auth.mixins import LoginRequiredMixin
①添加实现
导入类
dashboard/views.py
注意一定要最先继承LoginRequireMixin类
from django.shortcuts import render
from django.views.generic import View, TemplateView
from django.http import JsonResponse
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.mixins import LoginRequiredMixin
class BaseView(View):
def get(self,request):
return render(request,'base.html')
class IndexView(LoginRequiredMixin,TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
class LoginView(TemplateView):
template_name = 'login.html'
def post(self, request):
data = {}
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
data['status'] = 0
data['msg'] = "登陆成功"
else:
data['status'] = 1
data['msg'] = "账户或密码错误"
return JsonResponse(data)
配置修改默认登录路径
cmdb/settings.py
"""
Django settings for cmdb project.
Generated by 'django-admin startproject' using Django 4.2.6.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-79&mig28&5+94g*9zm4h8ey&@+cd5s7e8#wo&6)#_qcjnrf_h*'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'dashboard.apps.DashboardConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'cmdb.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [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',
],
},
},
]
WSGI_APPLICATION = 'cmdb.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cmdb',
'USER': 'root',
'PASSWORD': 'fxx123',
'HOST': '10.0.0.131',
'PORT': '3306',
'OPTIONS': {
"init_command": "SET sql_mode='STRICT_TRANS_TABLES'"
}
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
STATICFILES_DIRS = [
# os.path.join(BASE_DIR, 'static')
BASE_DIR / 'static'
]
LOGIN_URL = '/login/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
4、注销功能实现
注销退出登录功能,使用Django的logout方法实现即可。
注销后,返回登录页面,需要导入类方法
from django.http import HttpResponseRedirect
from django.urls import reverse
注销后通过HttpResponseRedirect跳转页面。
在跳转页面的同时,需要反向去解析URL别名,需要reverse解析方法。
视图
dashboard/views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.views.generic import View, TemplateView
from django.http import JsonResponse
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse
class BaseView(View):
def get(self,request):
return render(request,'base.html')
class IndexView(LoginRequiredMixin,TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['name'] = 'DevOps'
return context
class LoginView(TemplateView):
template_name = 'login.html'
def post(self, request):
data = {}
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
data['status'] = 0
data['msg'] = "登陆成功"
else:
data['status'] = 1
data['msg'] = "账户或密码错误"
return JsonResponse(data)
class LogoutView(View):
def get(self,request):
logout(request)
return HttpResponseRedirect(reverse('login'))
路由
cmdb/urls.py
from django.contrib import admin
from django.urls import path,include
from django.views.generic import RedirectView
from dashboard.views import *
urlpatterns = [
path('admin/', admin.site.urls),
path('',RedirectView.as_view(url='dashboard/')),
path('login/',LoginView.as_view(),name='login'),
path('logout/',LogoutView.as_view(),name='logout'),
path('dashboard/',include('dashboard.urls'))
]
模板
dashboard/templates/login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMDB管理系统</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/font-awesome/css/font-awesome.css" rel="stylesheet">
<link href="/static/css/plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="/static/css/animate.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/plugins/sweetalert/sweetalert.css">
{% block load_css %}
{% endblock %}
</head>
<body>
<div id="wrapper">
<nav class="navbar-default navbar-static-side" role="navigation">
<div class="sidebar-collapse">
<ul class="nav metismenu" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element" >
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">{{ request.user.username }}</strong>
</span> <span class="text-muted text-xs block">{{ request.user.groups.filter.0 }}<b class="caret"></b></span> </span>
</a>
<ul class="dropdown-menu animated fadeInRight m-t-xs">
<li><a href="profile.html">个人信息</a></li>
</ul>
</div>
</li>
<li>
<a href="{% url 'index' %}"><i class="fa fa-bar-chart-o"></i> <span class="nav-label">首页</span></a>
</li>
<li>
<a href="../dashboard/templates/index.html"><i class="fa fa-th-large"></i> <span class="nav-label">系统管理</span> <span
class="fa arrow"></span></a>
</li>
<li>
<a href="#"><i class="fa fa-bar-chart-o"></i> <span class="nav-label">资产管理</span><span
class="fa arrow"></span></a>
</li>
</ul>
</div>
</nav>
<div id="page-wrapper" class="gray-bg">
<div class="row border-bottom">
<nav class="navbar navbar-static-top " role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="#"><i class="fa fa-bars"></i>
</a>
</div>
<ul class="nav navbar-top-links navbar-right">
<li>
<span class="m-r-sm text-muted welcome-message">欢迎来到配置数据库管理系统 </span> </欢迎来到SYSCMDB自动化管理系统></span>
</li>
<a href="{% url 'logout' %}">
<i class="fa fa-sign-out"></i> 登出
</a>
</ul>
</nav>
</div>
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>仪表盘</h2>
<ol class="breadcrumb">
<li>
<a href="../dashboard/templates/index.html">首页</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<h1>这是BASE页面</h1>
{% endblock %}
</div>
</div>
<!-- Mainly scripts -->
<script src="/static/js/jquery-3.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/static/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<!-- Custom and plugin javascript -->
<script src="/static/js/inspinia.js"></script>
<script src="/static/js/plugins/pace/pace.min.js"></script>
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
function aaa(i){
console.log(i)
}
</script>
{% block load_js %}
{% endblock %}
</body>
</html>
5、登录原理解析(扩展)
会话机制,http每次连接默认没有上下联系状态。
cookie 存储在浏览器中的一些信息,具有风险,容易被篡改
session 存储到服务器的一些信息
通过查看相关信息,确认流程
退出登录的方式:
1、清空cookie
如果在浏览器清除了cookie信息,就会退出登录
cookie里记录了session_id,没有session_id就不能够找到session,所以就被判断为未登录
2、清空session
直接删除session信息,虽然cookie在,session没有了,也会判定为未登录
五、用户管理模块
1、展示用户列表
用户登录之后,继续实现用户管理模块。
首先展示用户列表信息,为了方便管理项目应用,创建新应用users,负责用户管理模块,用户组管理模块和权限管理模块的开发和管理。
创建新应用
python manage.py startapp users
配置允许应用
cmdb/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'dashboard.apps.DashboardConfig',
'users',
]
路由
cmdb/urls.py
from django.contrib import admin
from django.urls import path,include
from django.views.generic import RedirectView
from dashboard.views import *
urlpatterns = [
path('admin/', admin.site.urls),
path('',RedirectView.as_view(url='dashboard/')),
path('login/',LoginView.as_view(),name='login'),
path('logout/',LogoutView.as_view(),name='logout'),
path('dashboard/',include('dashboard.urls')),
path('users/',include('users.urls')),
]
users/urls.py
from django.urls import path
from users.views import *
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
]
视图
users/views.py
from django.shortcuts import render
from django.views.generic import TemplateView
class UserListView(TemplateView):
template_name = 'user_list.html'
模板
users/templates/user_list.html
{% extends 'base.html' %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{# {% for one in data %}#}
{# <tr>#}
{# <td class="text-center">{{ one.username }}</td>#}
{# <td class="text-center">{{ one.email }}</td>#}
{# <td class="text-center"></td>#}
{# <td class="text-center"></td>#}
{# <td class="text-center"></td>#}
{# {% if one.is_active == 1 %}#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# {% else %}#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# {% endif %}#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
<tr>
<td class="text-center">admin</td>
<td class="text-center">admin@qq.com</td>
<td class="text-center">admin123</td>
<td class="text-center">超级管理员</td>
<td class="text-center">13999999999</td>
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm">更新</button>
<button type="button" class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
上面实现了页面加载,获取数据库用户信息,显示到模板页面
视图
users/views.py
from django.shortcuts import render
from django.views.generic import View
from django.contrib.auth.models import User
# Create your views here.
class UserListView(View):
def get(self, request):
data = User.objects.all()
return render(request, 'user_list.html', {'data': data})
模板
users/templates/user_list.html
{% extends 'base.html' %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for one in data %}
<tr>
<td class="text-center">{{ one.username }}</td>
<td class="text-center">{{ one.email }}</td>
<td class="text-center"></td>
<td class="text-center"></td>
<td class="text-center"></td>
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm">更新</button>
<button type="button" class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
{% endfor %}
{# <tr>#}
{# <td class="text-center">admin</td>#}
{# <td class="text-center">admin@qq.com</td>#}
{# <td class="text-center">admin123</td>#}
{# <td class="text-center">超级管理员</td>#}
{# <td class="text-center">13999999999</td>#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
为了看到数据动态的效果,可以再通过 django添加用户测试
python manage.py createsuperuser
username: root
Password: 123.com
Password (again): 123.com
密码长度太短。密码必须包含至少 8 个字符。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
以下代码通过判断用户状态在页面显示用户是否处于激活状态,激活状态字段值为1 修改成其他值则会在页面显示红色
users/templates/user_list.html
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
mysql> update auth_user set is_active=0 where id=2;
2、扩展基础用户表
Django的用户表中,提供了基本必须字段:用户名称、邮箱、密码、角色(超级管理员、普通用户)
需要添加更多的用户信息,需要使用OneToOneField字段对用户表进行拓展。
OneToOneField就是一对一,跟多对一的使用类似,也有正向反向查询
扩展模型
加入中文名、微信、电话 备注等
导入基础用户模型
users/models.py
from django.db import models
from django.contrib.auth.models import User,Group
# Create your models here.
class Profile(models.Model): # 个人信息
user = models.OneToOneField(User,on_delete=models.CASCADE)
name_cn = models.CharField(max_length=32,verbose_name="中文名")
wechat = models.CharField(max_length=32,verbose_name="微信")
phone = models.CharField(max_length=11,verbose_name="电话")
info = models.TextField(verbose_name="备注")
迁移数据表
python manage.py makemigrations # 生成迁移表
python manage.py migrate # 进行数据迁移
插入数据
insert into users_profile values(null,'运维开发','fxx','18866568972','运维部',1);
修改模板
users/templates/user_list.html
{% extends 'base.html' %}
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for one in data %}
<tr>
<td class="text-center">{{ one.username }}</td>
<td class="text-center">{{ one.email }}</td>
<td class="text-center">{{ one.profile.wechat }}</td>
<td class="text-center">{{ one.profile.name_cn }}</td>
<td class="text-center">{{ one.profile.phone }}</td>
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm">更新</button>
<button type="button" class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
{% endfor %}
{# <tr>#}
{# <td class="text-center">admin</td>#}
{# <td class="text-center">admin@qq.com</td>#}
{# <td class="text-center">admin123</td>#}
{# <td class="text-center">超级管理员</td>#}
{# <td class="text-center">13999999999</td>#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
页面展示效果
3、高级视图类之ListView
上面的案例中使用高级视图类TemplateView,这里再使用另外一个高级视图类ListView
使用ListView 定义模型名称 数据会自动查询 并且组合
视图
users/views.py
from django.shortcuts import render
from django.views.generic import View,ListView
from django.contrib.auth.models import User
# class UserListView(View):
# def get(self, request):
# data = User.objects.all()
# return render(request, 'user_list.html', {'data': data})
class UserListView(ListView):
template_name = 'user_list.html'
model = User
def get_context_data(self, **kwargs):
content = super(UserListView, self).get_context_data(**kwargs)
print(content)
return content
模板
路由保持不变 修改模板遍历object_list
页面展示效果不变
4、批量创建用户
路由
users/urls.py
from django.urls import path
from users.views import *
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
path('testdata',TestDataView.as_view()),
]
视图
users/views.py
from django.shortcuts import render
from django.views.generic import View
from django.contrib.auth.models import User
# Create your views here.
class UserListView(View):
def get(self, request):
data = User.objects.all()
return render(request, 'user_list.html', {'data': data})
class TestDataView(View):
def get(self, request):
for i in range(1, 100):
user = User()
profile = Profile()
user.username = 'user{}'.format(i)
user.password = make_password('123456')
user.email = '{}.qq@com'.format(i)
user.save()
profile.user_id = user.id
profile.name_cn = '用户{}'.format(i)
profile.wechat = 'wechat_user{}'.format(i)
profile.phone = '133333333{}'.format(i)
profile.info = '测试用户{}'.format(i)
profile.save()
访问web页面创建用户
http://127.0.0.1:8000/users/testdata
5、分页实现
一次性展示数据太多了,需要进行分页显示处理。
分页原理
视图
通过高级视图ListView实现
users/views.py
class UserListView(ListView):
template_name = 'user_list.html'
model = User
paginate_by = 10 # 每页显示10条
def get_context_data(self, **kwargs):
content = super(UserListView, self).get_context_data(**kwargs)
print(content)
return content
显示页面按钮
page_obj.has_previous 判断是否有上一页
page_obj.previous_page_number 上一页的页数对象
page_obj.number 当前页数
page_obj.has_next 判断是否有下一页
page_obj.next_page_number 下一页的页面对象
paginator.num_pages 最大页数
paginator. page_range 可迭代的总页数
模板
users/templates/user_list.html
{% extends 'base.html' %}
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for one in object_list %}
<tr>
<td class="text-center">{{ one.username }}</td>
<td class="text-center">{{ one.email }}</td>
<td class="text-center">{{ one.profile.wechat }}</td>
<td class="text-center">{{ one.profile.name_cn }}</td>
<td class="text-center">{{ one.profile.phone }}</td>
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm">更新</button>
<button type="button" class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
{% endfor %}
{# <tr>#}
{# <td class="text-center">admin</td>#}
{# <td class="text-center">admin@qq.com</td>#}
{# <td class="text-center">admin123</td>#}
{# <td class="text-center">超级管理员</td>#}
{# <td class="text-center">13999999999</td>#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
</tbody>
</table>
</div>
</div>
</div>
<center>
<div class="btn-group">
{% if page_obj.has_previous %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.previous_page_number }}"><i
class="fa fa-chevron-left"></i></a>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<a class="btn btn-white active" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% else %}
<a class="btn btn-white" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.next_page_number }}"><i
class="fa fa-chevron-right"></i> </a>
{% endif %}
</div>
</center>
</div>
</div>
</div>
<script>
</script>
{% endblock %}
限制输出的页面按钮数量
视图
users/views.py
from django.shortcuts import render
from django.views.generic import View,ListView
from django.contrib.auth.models import User
from users.models import *
from django.contrib.auth.hashers import make_password,check_password
# Create your views here.
# class UserListView(View):
# def get(self, request):
# data = User.objects.all()
# return render(request, 'user_list.html', {'data': data})
class UserListView(ListView):
template_name = 'user_list.html'
model = User
paginate_by = 10 # 每页显示10条
def get_context_data(self, **kwargs):
content = super(UserListView, self).get_context_data(**kwargs)
print(content)
return content
def page_range(self, page_obj, paginator):
current_index = page_obj.number
start = current_index - 2
end = current_index + 3
if start <= 1:
start = 1
if end >= paginator.num_pages:
end = paginator.num_pages + 1
current_pages_num = end - start
if (end == paginator.num_pages + 1):
start = start - (5 - current_pages_num)
else:
if current_pages_num < 5:
end = end + (5 - current_pages_num)
return range(start, end)
class TestDataView(View):
def get(self, request):
for i in range(1, 100):
user = User()
profile = Profile()
user.username = 'user{}'.format(i)
user.password = make_password('123456')
user.email = '{}.qq@com'.format(i)
user.save()
profile.user_id = user.id
profile.name_cn = '用户{}'.format(i)
profile.wechat = 'wechat_user{}'.format(i)
profile.phone = '133333333{}'.format(i)
profile.info = '测试用户{}'.format(i)
profile.save()
6、添加用户
用户列表展示出来。之前创建用户是在命令行创建,实际业务中,需要在页面中添加用户。
点击添加按钮,通过表单结合ajax提交到后端,实现添加用户功能。
Tip:继承页面css和js处理
路由
users/urls.py
from django.urls import path
from users.views import *
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
path('add/', UserAddView.as_view(), name='user_add'),
]
视图
users/views.py
class UserAddView(TemplateView):
template_name = 'user_add.html'
def post(self, request):
data = request.POST
res = {'status': 0, 'msg': '添加成功'}
try:
user = User()
user.username = data.get('username')
user.password = make_password(data.get('password'))
user.mail = data.get('email')
user.save()
profile = Profile()
profile.user_id = user.id # 这里给 user_id 字段赋值
profile.name_cn = data.get('name_cn')
profile.wechat = data.get('wechat')
profile.phone = data.get('phone')
info = data.get('info')
if info is None or info == '': # 检查 'info' 字段是否为空
info = "默认值" # 给 'info' 字段赋值一个默认值
profile.info = info # 这里给 info 字段赋值
profile.save()
except Exception as e:
print(e)
res = {'status': 1, 'msg': '添加失败'}
return JsonResponse(res)
前端模板
users/templates/user_add.html
{% extends 'base.html' %}
{% block mbx %}
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>创建用户</h2>
<ol class="breadcrumb">
<li>
<a href="{% url 'index' %}">首页</a>
</li>
<li>
<a href="{% url 'user_list' %}">用户管理</a>
</li>
<li>
<a href="">创建用户</a>
</li>
</ol>
</div>
</div>
</div>
</div>
{% endblock %}
{% block body %}
<div class="ibox-content">
<form id="submit_form" class="form-horizontal">
{% csrf_token %}
<div class="form-group"><label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6"><input type="text" class="form-control" name="username"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">中文名</label>
<div class="col-sm-6"><input type="text" class="form-control" name="name_cn"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">密码</label>
<div class="col-sm-6"><input type="password" class="form-control" name="password"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-6"><input type="email" class="form-control" name="email"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">微信</label>
<div class="col-sm-6"><input type="text" class="form-control" name="wechat"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">电话</label>
<div class="col-sm-6"><input type="text" class="form-control" name="phone"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<a class="btn btn-white" type="submit" href="javascript:history.back(-1)">取消</a>
<button class="btn btn-primary" type="submit">保存更改</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block load_js %}
<script>
$(document).ready(function () {
$("#submit_form").validate({
rules: {
name_cn: {
required: true
},
username: {
required: true
},
email: {
required: true
},
password: {
required: true
},
phone: {
required: true,
minlength:11
},
wechat: {
required: true
}
}, submitHandler: function () {
var str = $('#submit_form').serialize();
$.post('{% url 'user_add' %}', str, function (res) {
if (res.status == 0) {
swal({
title: res.msg,
type: 'success',
confirmButtonText: "确定"
}, function () {
window.location.href = '{% url 'user_list' %}';
});
} else {
swal({
title: res.msg,
type: 'error',
confirmButtonText: "确定"
});
}
});
}
});
});
</script>
{% endblock %}
user_list增加一个添加用户的跳转按钮
users/templates/user_list.html
{% extends 'base.html' %}
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<a type="butten" class="btn btn-info" href="{% url 'user_add' %}">添加用户</a>
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for one in object_list %}
<tr>
<td class="text-center">{{ one.username }}</td>
<td class="text-center">{{ one.email }}</td>
<td class="text-center">{{ one.profile.wechat }}</td>
<td class="text-center">{{ one.profile.name_cn }}</td>
<td class="text-center">{{ one.profile.phone }}</td>
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm">更新</button>
<button type="button" class="btn btn-danger btn-sm">删除</button>
</td>
</tr>
{% endfor %}
{# <tr>#}
{# <td class="text-center">admin</td>#}
{# <td class="text-center">admin@qq.com</td>#}
{# <td class="text-center">admin123</td>#}
{# <td class="text-center">超级管理员</td>#}
{# <td class="text-center">13999999999</td>#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
</tbody>
</table>
</div>
</div>
</div>
<center>
<div class="btn-group">
{% if page_obj.has_previous %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.previous_page_number }}"><i
class="fa fa-chevron-left"></i></a>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<a class="btn btn-white active" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% else %}
<a class="btn btn-white" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.next_page_number }}"><i
class="fa fa-chevron-right"></i> </a>
{% endif %}
</div>
</center>
</div>
</div>
</div>
<script>
</script>
{% endblock %}
7、更新用户
路由
users/urls.py
from django.urls import path
from users.views import *
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
path('add/', UserAddView.as_view(), name='user_add'),
path('update/', UserUpdateView.as_view(), name='user_update'),
]
视图
users/views.py
class UserUpdateView(View):
def get(self, request):
return render(request, 'user_update.html', {'user_obj': User.objects.get(id=request.GET.get('id'))})
def post(self, request):
data = request.POST
res = {'status': 0, 'msg': '修改成功'}
try:
user = User.objects.get(id=data.get('uid'))
profile = Profile.objects.get(user_id=data.get('uid'))
user.username = data.get('username')
user.password = make_password(data.get('password'))
user.mail = data.get('email')
user.save()
profile.profile_id = user.id
profile.name_cn = data.get('name_cn')
profile.wechat = data.get('wechat')
profile.phone = data.get('phone')
info = data.get('info')
if info is None:
# 将info设为NULL或者设置一个默认值
info = ''
profile.info = info
profile.save()
except Exception as e:
print(e)
res = {'status': 1, 'msg': '修改失败'}
return JsonResponse(res)
前端模板
user_update.html模板
{% extends 'base.html' %}
{% block load_css %}
<link href="/static/css/plugins/sweetalert/sweetalert.css" rel="stylesheet">
{% endblock %}
{% block body %}
<h1>更新用户:{{ user_obj.username }}</h1>
<div class="ibox-content">
<form id="submit_form" class="form-horizontal">
{% csrf_token %}
<div class="form-group"><label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6"><input type="text" class="form-control" name="username" value="{{ user_obj.username }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">中文名</label>
<div class="col-sm-6"><input type="text" class="form-control" name="name_cn" value="{{ user_obj.profile.name_cn }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">密码</label>
<div class="col-sm-6"><input type="password" class="form-control" name="password"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-6"><input type="email" class="form-control" name="email" value="{{ user_obj.email }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">微信</label>
<div class="col-sm-6"><input type="text" class="form-control" name="wechat" value="{{ user_obj.profile.wechat }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">电话</label>
<div class="col-sm-6"><input type="text" class="form-control" name="phone" value="{{ user_obj.profile.phone }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">简介</label>
<div class="col-sm-6"><input type="text" class="form-control" name="info" value="{{ user_obj.profile.info }}"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<input type="hidden" value="{{ user_obj.id }}" name="uid">
<a class="btn btn-white" type="submit" href="javascript:history.back(-1)">取消</a>
<button class="btn btn-primary" type="submit">保存更改</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block load_js %}
<script src="/static/js/plugins/validate/jquery.validate.js"></script>
<script src="/static/js/plugins/validate/messages_zh.js"></script>
<script src="/static/js/plugins/sweetalert/sweetalert.min.js"></script>
<script>
$(document).ready(function () {
$("#submit_form").validate({
rules: {
name_cn: {
required: true
},
username: {
required: true
},
email: {
required: true
},
password: {
required: true
},
phone: {
required: true
},
wechat: {
required: true
}
}, submitHandler: function () {
var str = $('#submit_form').serialize();
$.post('{% url 'user_update' %}', str, function (res) {
if (res.status == 0) {
swal({
title: res.msg,
type: 'success',
confirmButtonText: "确定"
}, function () {
window.location.href = '{% url 'user_list' %}';
});
} else {
swal({
title: res.msg,
type: 'error',
confirmButtonText: "确定"
});
}
});
}
});
});
</script>
{% endblock %}
user_list模板修改跳转链接
<a type="button" class="btn btn-primary btn-sm" href="{% url 'user_update' %}?id={{ one.id }}">更新</a>
8、删除用户
路由
users/urls.py
from django.urls import path
from users.views import *
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
path('add/', UserAddView.as_view(), name='user_add'),
path('update/', UserUpdateView.as_view(), name='user_update'),
path('delete/', UserDeleteView.as_view(), name='user_delete'),
]
视图
users/views.py
class UserDeleteView(View):
def get(self, request):
uid = request.GET.get('uid')
res = {'status': 0, 'msg': "更新成功"}
try:
User.objects.get(id=uid).delete()
print(User.DoesNotExist)
except User.DoesNotExist:
res = {'status': 1, 'msg': '用户不存在,删除失败'}
except Exception:
res = {'status': 1, 'msg': '未知错误'}
return JsonResponse(res)
模板
<a type="button" class="btn btn-danger btn-sm" onclick="user_delete({{ one.id }})">删除</a>
删除函数
users/templates/user_list.html
{% extends 'base.html' %}
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
{% block mbx %}
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>用户展示</h2>
<ol class="breadcrumb">
<li>
<a hreaf="{% url 'index' %}">首页</a>
</li>
<li>
<a href="">用户管理</a>
</li>
<li>
<a href="">用户展示</a>
</li>
</ol>
</div>
</div>
{% endblock %}
{% block body %}
<a type="butten" class="btn btn-info" href="{% url 'user_add' %}">添加用户</a>
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户展示 </h5>
</div>
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">用户名</th>
<th class="text-center">邮箱</th>
<th class="text-center">微信</th>
<th class="text-center">中文名</th>
<th class="text-center">电话</th>
<th class="text-center">激活状态</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for one in object_list %}
<tr>
<td class="text-center">{{ one.username }}</td>
<td class="text-center">{{ one.email }}</td>
<td class="text-center">{{ one.profile.wechat }}</td>
<td class="text-center">{{ one.profile.name_cn }}</td>
<td class="text-center">{{ one.profile.phone }}</td>
{% if one.is_active == 1 %}
<td class="text-center"><i class="fa fa-circle text-navy"></i></td>
{% else %}
<td class="text-center"><i class="fa fa-circle text-danger"></i></td>
{% endif %}
<td class="text-center">
<a type="button" class="btn btn-primary btn-sm" href="{% url 'user_update' %}?id={{ one.id }}">更新</a>
<a type="button" class="btn btn-danger btn-sm" onclick="user_delete({{ one.id }})">删除</a>
</td>
</tr>
{% endfor %}
{# <tr>#}
{# <td class="text-center">admin</td>#}
{# <td class="text-center">admin@qq.com</td>#}
{# <td class="text-center">admin123</td>#}
{# <td class="text-center">超级管理员</td>#}
{# <td class="text-center">13999999999</td>#}
{# <td class="text-center"><i class="fa fa-circle text-navy"></i></td>#}
{# <td class="text-center"><i class="fa fa-circle text-danger"></i></td>#}
{# <td class="text-center">#}
{# <button type="button" class="btn btn-primary btn-sm">更新</button>#}
{# <button type="button" class="btn btn-danger btn-sm">删除</button>#}
{# </td>#}
{# </tr>#}
</tbody>
</table>
</div>
</div>
</div>
<center>
<div class="btn-group">
{% if page_obj.has_previous %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.previous_page_number }}"><i
class="fa fa-chevron-left"></i></a>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<a class="btn btn-white active" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% else %}
<a class="btn btn-white" href="{% url 'user_list' %}?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a type="button" class="btn btn-white"
href="{% url 'user_list' %}?page={{ page_obj.next_page_number }}"><i
class="fa fa-chevron-right"></i> </a>
{% endif %}
</div>
</center>
<script>
function user_delete(id) {
if (confirm('确认删除吗?')) {
{#alert(id)#}
$.get("{% url 'user_delete' %}?id=" + id,function (data) {
if(data.status == 0) {
swal({
title: data.msg,
icon: "success",
confirmButtonText: '确定',
}, function () {
window.location.reload()
});
} else {
swal("删除失败", {
icon: "error",
});
}
});
}
}
</script>
{% endblock %}
9、禁用和启用用户
路由
urlpatterns = [
path('list/', UserListView.as_view(), name='user_list'),
path('add/', UserAddView.as_view(), name='user_add'),
path('update/', UserUpdateView.as_view(), name='user_update'),
path('delete/', UserDeleteView.as_view(), name='user_delete'),
path('status/',UserStatusView.as_view(),name='user_status'),
]
视图
class UserStatusView(View):
def get(self, request):
data = request.GET
# 判断当前用户是禁用还是启用
# 用户是禁用则启用 用户是启用则禁用
res = {'status': 0, 'msg': '用户状态更新成功'}
# 查询用户当前状态
user = User.objects.get(id=data.get('id'))
status = user.is_active
# 确定用户跟新的新状态
if status == 0:
newstatus = 1
else:
newstatus = 0
try:
user = User.objects.get(id=data.get('id'))
user.is_active = newstatus
user.save()
except Exception as e:
print(e)
res = {'status': 1, 'msg': '用户状态更新失败'}
return JsonResponse(res)
模板
增加两个按钮,查询状态如果用户是启用状态则显示禁用按钮,如果用户是禁用状态则显示启用按钮
在
function user_status(id) {
$.get("{% url 'user_status' %}?id=" + id,function (data) {
if(data.status == 0) {
swal({
title: data.msg,
icon: "success",
confirmButtonText: '确定',
}, function () {
window.location.reload()
});
} else {
swal({
title: data.msg,
icon: "error",
confirmButtonText: '确定',
},function () {
});
}
});
}