CRM---系统 登录 注册
Customer Relationship Managemen
一. 准备工作
1.新建一个IgCrm的Django项目
2.配置数据库
使用mysql,安装pymysql库,
'IgCrm.__init__.py'
import pymysql pymysql.install_as_MySQLdb()
setting.py
# 数据库连接,数据库要先建好 DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'IgCrm', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': 3306 } }
3.扩展auth.User表
django自带的User表,有时满足不了我们的需求,我们可以使用继承的方式扩展User表
先配置setting.py,指定那张表管理Django用户认证
setting
# 指定Django使用那张表进行用户验证管理 AUTH_USER_MODEL = "app01.UserInfo"
modle.py
from django.db import models # 默认的User表也继承于这个类 from django.contrib.auth.models import AbstractUser # Create your models here. # 继承关系 class UserInfo(AbstractUser): telephone = models.CharField(max_length=16) address = models.CharField(max_length=60) gender = models.BooleanField()
执行命令迁移数据库
-
makemigrations
-
migrate


可以发现之前的auth_user表没有了,是由于我们使用了app01_userinfo作为用户认证的表,userinfo表即继承了原来user表的字段,也有了自定义的字段。
4.配置静态资源目录
setting.py
STATIC_URL = '/static/' # 使用static别名,制定静态资源路径 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]
5.下载一套后台模版
将模版文件夹中的html文件放到templates目录,css,js,fonts,img等静态资源文件放到static目录下

二.登录功能
1.需求:
- 基于ajax请求的页面无刷新登录
- 实现验证码功能
2.修改login.html模版
模版原样式:

原模版代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="Mosaddek"> <meta name="keyword" content="FlatLab, Dashboard, Bootstrap, Admin, Template, Theme, Responsive, Fluid, Retina"> <link rel="shortcut icon" href="img/favicon.html"> <title>FlatLab - Flat & Responsive Bootstrap Admin Template</title> <!-- Bootstrap core CSS --> <link href="css/bootstrap.min.css" rel="stylesheet"> <link href="css/bootstrap-reset.css" rel="stylesheet"> <!--external css--> <link href="assets/font-awesome/css/font-awesome.css" rel="stylesheet" /> <!-- Custom styles for this template --> <link href="css/style.css" rel="stylesheet"> <link href="css/style-responsive.css" rel="stylesheet" /> <!-- HTML5 shim and Respond.js IE8 support of HTML5 tooltipss and media queries --> <!--[if lt IE 9]> <script src="js/html5shiv.js"></script> <script src="js/respond.min.js"></script> <![endif]--> </head> <body class="login-body"> <div class="container"> <form class="form-signin" action="index.html"> <h2 class="form-signin-heading">sign in now</h2> <div class="login-wrap"> <input type="text" class="form-control" placeholder="User ID" autofocus> <input type="password" class="form-control" placeholder="Password"> <label class="checkbox"> <input type="checkbox" value="remember-me"> Remember me <span class="pull-right"> <a href="#"> Forgot Password?</a></span> </label> <button class="btn btn-lg btn-login btn-block" type="submit">Sign in</button> <p>or you can sign in via social network</p> <div class="login-social-link"> <a href="index.html" class="facebook"> <i class="icon-facebook"></i> Facebook </a> <a href="index.html" class="twitter"> <i class="icon-twitter"></i> Twitter </a> </div> </div> </form> </div> </body> </html>
修改后的模版代码:
- 修改外链资源的路径
- 修改form表单提交按钮的input标签的type为button
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="Mosaddek"> <meta name="keyword" content="FlatLab, Dashboard, Bootstrap, Admin, Template, Theme, Responsive, Fluid, Retina"> <link rel="shortcut icon" href="/static/img/favicon.html"> <title>FlatLab - Flat & Responsive Bootstrap Admin Template</title> <!--注意原模版中的外链资源,路径地址全部都要修改--> <!-- Bootstrap core CSS --> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-reset.css" rel="stylesheet"> <!--external css--> <link href="/static/assets/font-awesome/css/font-awesome.css" rel="stylesheet"/> <!-- Custom styles for this template --> <link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style-responsive.css" rel="stylesheet"/> <script src="/static/js/jquery.js"></script> <!-- HTML5 shim and Respond.js IE8 support of HTML5 tooltipss and media queries --> <!--[if lt IE 9]> <script src="/static/js/html5shiv.js"></script> <script src="/static/js/respond.min.js"></script> <![endif]--> </head> <body class="login-body"> <div class="container"> <form class="form-signin" action="index.html"> <h2 class="form-signin-heading">sign in now</h2> <!--由于是post请求,需要加入csrf_token通过验证--> {% csrf_token %} <div class="login-wrap"> <!--用户名--> <input type="text" class="form-control" required placeholder="User ID" id="user" autofocus> <!--密码--> <input type="password" class="form-control" id="password" placeholder="Password"> <!--验证码--> <div class="row"> <div class="col-md-6"> <!--用户输入验证码--> <input type="text" class="form-control" id="code" placeholder="验证码" autofocus> </div> <div class="col-md-6"> <!--验证码图片--> <img src="/get_valid_code/" alt="" id="valid-code" title="点击刷新验证码"> </div> </div> <label class="checkbox"> <input type="checkbox" value="remember-me"> Remember me <span class="pull-right"> <a href="#"> Forgot Password?</a></span> </label> <!--如果用form表单还想发送ajax请求,必须把使用input标签type为button的按钮,input标签type为submit和button标签都会触发form的action操作--> <input type="button" class="btn btn-lg btn-login btn-block" id="login-btn" value="Sign in"> <!--显示验证验证错误信息--> <span id="error-msg"></span> <p>or you can sign in via social network</p> <div class="login-social-link"> <a href="index.html" class="facebook"> <i class="icon-facebook"></i> Facebook </a> <a href="index.html" class="twitter"> <i class="icon-twitter"></i> Twitter </a> </div> </div> </form> </div> <!--引用自己写的JS文件--> <script src="/static/js/owner_js/login.js"></script> </body> </html>

3.验证码生成
- 验证码生成基于PIL模块完成,安装pillow就可以使用PIL了
验证码生成代码
validcode.py
from PIL import Image, ImageDraw, ImageFont from io import BytesIO import random def get_valid_img(): # 随机颜色 def get_random_color(): return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) # 创建画布 img = Image.new("RGB", (130, 38), get_random_color()) # 创建画笔 draw = ImageDraw.Draw(img) # 设置所使用的字体 font = ImageFont.truetype("static/fonts/kumo.ttf", 32) # 保存验证码对应的字符 keep_str = "" # 开始绘画 for i in range(4): # 随机数字 random_num = str(random.randint(0, 9)) # 随机小写字母 random_lowalf = chr(random.randint(97, 122)) # 随机大写字母 random_upperalf = chr(random.randint(65, 90)) # 4个随你字符中选取一个 random_char = random.choice([random_num, random_lowalf, random_upperalf]) # 参数说明: 1.字符位于画布中的坐标,画布左上角为0,0 2.字符 3.设置画布背景颜色 4.字符所使用字体 draw.text((i * 30 + 20, 0), random_char, get_random_color(), font=font) keep_str += random_char ## 随机线条 # width = 130 # height = 38 # for i in range(10): # x1 = random.randint(0, width) # x2 = random.randint(0, width) # y1 = random.randint(0, height) # y2 = random.randint(0, height) # draw.line((x1, y1, x2, y2), fill=get_random_color()) ## 随机噪点 # for i in range(100): # draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) # x = random.randint(0, width) # y = random.randint(0, height) # draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color()) # 创建内存对象 f = BytesIO() # 将生成的验证码图片保存到内存对象中 img.save(f, "png") # 获取到这个内存对象 data = f.getvalue() # 返回内存对象,和验证码对应的字符串 return data, keep_str
4.设置路由
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), # 登录 path('login/', views.login, name='login'), # 验证码 path('get_valid_code/', views.get_valid_code), path('', views.index) ]
5.视图函数
- 使用session存储生成的验证码字符串,用户提交alax请求带着session_id过来的,取出对应的验证码字符串,进行匹配
- 返回最终验证数据,使用了JsonResponse模块,减少了我们封装json数据的过程,JsonResponse给响应头封装了一个content_type='application/json'的响应头,客户端接受到响应后会自动根据这个响应头进行处理,无需我们再进行反序列化
- 使用django认证组件进行验证用户
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth from django.http import JsonResponse from django.urls import reverse from app01 import validcode # Create your views here. # 用户登录 def login(request): # 客户端提交的ajax请求 if request.is_ajax(): # 获取客户端上传上来的数据 user = request.POST.get('user') pwd = request.POST.get('pwd') code = request.POST.get('code') # 返回给客户端的数据字典 response = {'user': None, 'error_msg': ''} # 验证码是否匹配 if code.upper() == request.session.get('keep_str').upper(): # 验证用户名 if auth.authenticate(username=user, password=pwd): response['user'] = user else: response['error_msg'] = '用户名或密码错误' else: response['error_msg'] = '验证码错误' # 使用JsonResponse返回一个json字符串数据 return JsonResponse(response) else: return render(request, 'login.html') # 跳转login def index(request): return redirect(reverse('login')) # 返回验证码 def get_valid_code(request): # 调用方法返回验证码图片内存对象,和验证码字符串 code_img, keep_str = validcode.get_valid_img() # 使用验证码字符串设置session # 该操作的进行的3个步骤 # 1.将验证码字符串变成键值对并加密插到session中生成一条记录,键值对字段名为session_data,并给该条记录的session_key字段添加一个随机字符串,如果表中已存在对应的session_key已存在则更新session_data # 2.返回session_key # 2.给响应体添加一个session_id=session_key的cookie request.session['keep_str'] = keep_str # 返回验证码响应体 return HttpResponse(code_img)
6.前端JS代码
$(function () { // 刷新验证码 $('#valid-code').click(function () { this.src += '?' }); $('#login-btn').click(function () { $.ajax({ url: '', type: 'post', data: { user: $('#user').val(), pwd: $('#password').val(), code: $('#code').val(), csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val() }, success: function (response) { if (response.user) { location.href = 'http://www.baidu.com' } else { $('#error-msg').text(response.error_msg).css('color', 'red') } } }) }); // 输入框获得焦点,移除错误信息 $('#user,#password,#code').focus(function () { $('#error-msg').text('') }); });
三. 注册功能
1.需求
- 基于ajax的数据提交
- 基于django forms的表单数据校验,及表单标签渲染
2.新增路由
urls.py
# 注册 path('reg/', views.reg, name='reg'),
3. 创建forms表单组件
forms_check.py
from django import forms from django.forms import widgets from app01.models import UserInfo from django.core.exceptions import ValidationError import re # 创建一个forms组件类 class FormCheck(forms.Form): # 用户名 username = forms.CharField(min_length=4, max_length=16, label='用户名:', error_messages={'required': '用户名不能为空', 'min_length': '用户名不能少于4位'}, widget=widgets.TextInput(attrs={'placeholder': "用户名为4~16为位"}) ) # 校验密码 password = forms.CharField(min_length=6, max_length=16, label='密码:', error_messages={'required': '密码不能为空', 'min_length': '密码不能少于6位'}, widget=widgets.PasswordInput(attrs={'placeholder': "密码为6~16位"}) ) # 校验确认密码 confirm_password = forms.CharField(min_length=6, max_length=16, label='确认密码:', error_messages={'required': '密码不能为空', 'min_length': '密码不能少于6位'}, widget=widgets.PasswordInput(attrs={'placeholder': "请确认密码"})) # 校验邮箱 email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}, label='邮箱', widget=widgets.EmailInput(attrs={'placeholder': "请输入邮箱邮箱"})) # 校验手机号 telephone = forms.CharField(label='手机号码:', error_messages={'required': '手机号不能为空'}, widget=widgets.TextInput(attrs={'placeholder': "请输入手机号"})) # 给所有字段添加form-control类 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for filed in self.fields.values(): filed.widget.attrs.update({'class': 'form-control'}) # 校验用户名是否已存在(局部钩子) def clean_username(self): val = self.cleaned_data.get('username') if UserInfo.objects.filter(username=val).first(): raise ValidationError('用户名已存在') else: return val # 校验密码不能位纯数字 def clean_password(self): val = self.cleaned_data.get('password') if val.isdigit(): raise ValidationError('密码不能为纯数字') else: return val # 校验邮箱格式 def clean_email(self): val = self.cleaned_data.get('email') if re.search(r'^[\w.\-]+@(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,3}$', val): return val else: raise ValidationError('无效的邮箱') # 校验手机号格式 def clean_telephone(self): val = self.cleaned_data.get('telephone') if re.search(r'^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$', val): return val else: raise ValidationError('无效的手机号') # 校验两次密码是否一致(全局钩子) def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if password and confirm_password and password != confirm_password: self.add_error('confirm_password', ValidationError('两次密码不一致')) else: return self.cleaned_data
4.视图函数
views.py
# 用户注册 def reg(request): # 接收到ajax请求 if request.is_ajax(): # 使用forms对象对post请求体中的数据进行校验 form_check = FormCheck(request.POST) # 响应的数据字典 response = {'user': None, 'error_msg': ''} # 所有表单校验都通过 if form_check.is_valid(): # 到数据库插入一条用户记录数据 username = request.POST.get('username') password = request.POST.get('password') email = request.POST.get('email') telephone = request.POST.get('telephone') UserInfo.objects.create_user(username=username, password=password, email=email, telephone=telephone) # 响应体数据字典的user的None改为用户名 response['user'] = form_check.cleaned_data.get('username') else: # 有表单验证错误的情况,响应体数据字典的error_msg设置值为校验错误信息 response['error_msg'] = form_check.errors # 最后返回响应体数据字典 return JsonResponse(response) else: # 创建forms对象 forms = FormCheck() # 返回页面及forms对象,到页面进行标签渲染 return render(request, 'reg.html', locals())
5.前端页面
- 先写静态标签页面,调好样式,然后再使用forms组件修改渲染页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content="Mosaddek"> <meta name="keyword" content="FlatLab, Dashboard, Bootstrap, Admin, Template, Theme, Responsive, Fluid, Retina"> <link rel="shortcut icon" href="/static/img/favicon.html"> <title>FlatLab - Flat & Responsive Bootstrap Admin Template</title> <!--注意原模版中的外链资源,路径地址全部都要修改--> <!-- Bootstrap core CSS --> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-reset.css" rel="stylesheet"> <!--external css--> <link href="/static/assets/font-awesome/css/font-awesome.css" rel="stylesheet"/> <!-- Custom styles for this template --> <link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style-responsive.css" rel="stylesheet"/> <script src="/static/js/jquery.js"></script> <!-- HTML5 shim and Respond.js IE8 support of HTML5 tooltipss and media queries --> <!--[if lt IE 9]> <script src="/static/js/html5shiv.js"></script> <script src="/static/js/respond.min.js"></script> <![endif]--> </head> <body class="login-body"> <div class="container"> <form class="form-horizontal form-signin form-signup" action="index.html"> <h2 class="form-signin-heading">sign up now</h2> <!--由于是post请求,需要加入csrf_token通过验证--> {% csrf_token %} <div class="login-wrap"> <!--遍历forms对象中的每个字段生成input标签--> {% for field in forms %} <div class="form-group"> <!--field.auto_id为对应的input的id属性--> <!--field.label后端该字段设置的label值--> <label for="{{ field.auto_id }}" class="col-sm-2 control-label signup-label">{{ field.label }}</label> <div class="col-sm-10"> <!--field为input字段--> {{ field }} <span class="error-msg pull-right"></span> </div> </div> {% endfor %} <!--密码--> <!-- <input type="password" class="form-control" required id="password" placeholder="密码"> --> <!--如果用form表单还想发送ajax请求,必须把使用input标签type为button的按钮,input标签type为submit和button标签都会触发form的action操作--> <a href="/login/" class="pull-right re-login">已有帐号?马上登录</a> <input type="button" class="btn btn-lg btn-login btn-block" id="signup-btn" value="提交"> <!--显示验证验证错误信息--> </div> </form> </div> <!--引用自己写的JS文件--> <script src="/static/js/owner_js/reg.js"></script> </body> </html>
6.前端js代码
$(function () {
// 点击注册发送ajax请求
$('#signup-btn').click(function () {
$.ajax({
url: '',
type: 'post',
data: {
username: $('#id_username').val(),
password: $('#id_password').val(),
confirm_password: $('#id_confirm_password').val(),
email: $('#id_email').val(),
telephone: $('#id_telephone').val(),
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
success: function (response) {
if (response.user) {
alert('注册成功!');
location.href = '/login/'
} else {
// 渲染报错信息
$.each(response.error_msg, function (i, j) {
$('#id_' + i).next().html(j[0]).css('color','red').parent().addClass('has-error')
})
}
}
})
});
// input获得鼠标焦点,移除校验错误
$('.login-wrap input').focus(function () {
$(this).next().html('').parent().parent().removeClass('has-error')
})
});

浙公网安备 33010602011771号