0%

Django CRM实战|Day3:注册-验证-登录模块实现

实现用户注册,用户名邮箱合法性检查,用户名密码验证,登录的功能。涉及前端的js和后端数据库的操作。

登录模块是一个应用,而目前为止我们所创建的是一个项目,因此需要首先创建一个应用。

为你的系统创建一个系统应用


DJango会在项目下生成一个manage.py的文件,在该文件的路径下运行如下代码,可以生成一个应用:

在Setting.py中配置应用

这步会导致报错,不进行反而能按照预期正常运行

在Setting.py文件的INSTALLED_APPS下增加我们新建的system应用:

在url.py中进行配置

按照如下方式配置url.py

这里的意思是:

  • 如果url为admin/,将被转向admin.site.urls
  • 否则url将被转向system应用下的urls文件进行匹配

函数path

函数 path() 具有四个参数:

  • route:route 是一个匹配 URL 的准则(类似正则表达式)。当 Django 响应一个请求时,它会从 urlpatterns 的第一项开始,按顺序依次匹配列表中的项,直到找到匹配的项。
  • view:当 Django 找到了一个匹配的准则,就会调用这个特定的视图函数,并传入一个 HttpRequest 对象作为第一个参数,被“捕获”的参数以关键字参数的形式传入。
  • kwargs(*):任意个关键字参数可以作为一个字典传递给目标视图函数。
  • name(*):为你的 URL 取名能使你在 Django 的任意地方唯一地引用它,尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个 URL 模式。

定义登录功能


在Django框架下开发一项功能,从后端到前端的流程应该是:
SQL → 视图 → 映射 → 模板 → 测试
下面我们将遵循这样的流程顺序进行开发。

这里将使得我们的应用能够跳转到登录界面,并实现一些登录名密码验证的功能,那么我们首先需要有一个html界面,可以实现最基本的用户名、密码输入的功能,这里附上一个免费的前端模板库,可以在里面找到现成的登录界面以便快速开始开发。

注册模板 - 网站模板 - 源码之家

下载下来的界面会是html格式的文件,将该文件放到项目的template文件夹下,同时可能附带一些CSS文件或者其他资源,这些资源一概放到static文件夹下。

定义用户的模型

在登录模块,最主要的模型就是用户(账号),这里我们找到项目中system文件夹下的models.py文件,在其中对用户进行定义。

新建一个User类,简单地定义它由「用户名」,「密码」和「创建时间」三种信息构成:

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models
from datetime import datetime
# Create your models here.

class User(models.Model):
user_name = models.CharField(max_length=30, db_column='user_name')
password = models.CharField(max_length=30)
create_time = models.DateTimeField(default=datetime.now().date())

#连接到user表
class Meta(object):
db_table = 'user'

注意这里字段的类型和长度设定需要与数据库中相一致:

定义视图

修改views.py文件:

1
2
3
4
5
6
from django.shortcuts import render

# Create your views here.
#跳转页面
def login(request):
return render(request,'login.html')

定义映射

system下新建一个url.py,按如下方式配置:

1
2
3
4
5
6
7
8
from django.urls import path
from . import views

app_name ='system'

urlpatterns = [
path('login/', views.login, name='login'),
]

此时登录界面已完成,运行项目,在浏览器输入http://127.0.0.1:8000/login/就可以从服务器访问我们的登录界面,例如我在自己的电脑上访问改地址:

有时会碰到html页面在本地显示正常在服务器上却没有更新的情况,这时候清理浏览器缓存或许可以解决

注册验证


注册名、邮箱及密码合法性验证

这里我们将实现注册时的验证问题,简单地实现四个合法性判断:

  • 账号不为空
  • 邮箱不为空,且格式正确
  • 密码不为空
  • 确认密码需与密码一致

实现的逻辑为,首先从页面中获取用户的输入,将其赋值到某一变量,判断变量是否符合我们的标准。

那么如何找到页面中用户的输入呢?

以用户名为例,首先在chrome中打开我们的页面,在页面上右键选择「检视」,进入开发者模式。

选中用户名输入框发现定位到如下位置:

说明用户名输入框的iduser,下面我们就可以通过这个id对用户名进行读取。

  1. 下面实现判断用户名是否为空。

该判断应该在用户完成输入,也就是用户先选中用户名输入框,完成输入后再将焦点转向其他位置时进行。这就要用到JS的模糊焦点功能,需要首先导入jquery依赖,即将所需要的js文件放在项目内,然后在html文档内调用,js文件一般在下载下来的模板中有,或可以自行搜索下载。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--导入jquery支持-->
<script type="text/javascript" src="../static/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="../static/js/jquery.cookie.js"></script>
<script type="text/javascript">
//验证注册合法性
function check_username() {
user_name = $('#username_reg').val(); //$是getelementbyid的一种简便写法
if($.trim(user_name)==''||$.trim(user_name)==null){
$('#notice').html('用户名不能为空'); //notice是我自己添加的一个span标签,用来显示文本提示
return false;
}
else{
$('#notice').html('');//检测到用户名不为空后将提示清空
return true;
}
}
$('#username_reg').on('blur', check_username);
</script>

注意该段代码必须写在主体部分之外。

这里涉及到一个相对路径的问题,我把.js文件放在static文件夹下的js文件夹内,这些文件与login.html界面的层级关系如下图所示,login.html要访问到js文件,必须要先返回上级目录再进入js目录:

1
../static/js/jquery-3.5.1.min.js

../表示进入返回上级目录,./表示同级目录

  1. 对于邮箱,除了判断是否为空外,还要验证邮箱格式是否符合xx@xx.xx的样式,一般用正则表达式实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
functioncheck_email() {
email =$('#email_reg').val();
var reg = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
if($.trim(email)==''||$.trim(email)==null){
$('#notice').html('邮箱不能为空');
return false;
}
else if(!reg.test(email)){
$('#notice').html('请输入正确格式的邮箱');
return false;
}
else{
$('#notice').html('');
return true;
}
}
$('#email_reg').on('blur', check_email);

注意这些代码都必须在导入的js依赖里。

  1. 接着验证密码是否为空:
1
2
3
4
5
6
7
8
9
10
11
12
13
functioncheck_password() {
pass_word =$('#password_reg').val();
if ($.trim(pass_word)==''||$.trim(pass_word)==null){
$('#notice').html('密码不能为空');
{#alert('密码不能为空');#}
return false;
}
else{
$('#notice').html('');
return true;
}
}
$('#password_reg').on('blur', check_password);
  1. 验证确认密码是否与密码一致:
1
2
3
4
5
6
7
8
9
10
11
12
13
functioncheck_confirm_password() {
pass_word =$('#password_reg').val();
confirm_pass_word =$('#con_password_reg').val();
if ($.trim(confirm_pass_word)!=pass_word){
$('#notice').html('密码不一致');
return false;
}
else{
$('#notice').html('');
return true;
}
}
$('#con_password_reg').on('blur', check_confirm_password);

验证用户名是否唯一

验证用户名是否唯一,需要从前端获取用户输入,再发送给服务器的数据库进行验证。在代码逻辑上,我们将从页面login.html获取输入,通过ajax发送给服务器,在views.py中实现对发送数据的获取以及在服务器中的查询,然后将查询的结果返回前端login.html进行相应的输出。

views.py中新增视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.views.decorators.http import require_POST
from .models import User

#验证用户名是否唯一
@require_POST
def unique(request):
try:
#接收参数
type = request.POST.get('check_type')
if type=='username':
user_name = request.POST.get('info')
#查询用户
user = User.objects.get(user_name = user_name)
#有用户返回页面json
return JsonResponse({'code':400, 'msg':'验证失败'})
elif type=='email':
email = request.POST.get('info')
email_ = User.objects.get(email = email)
return JsonResponse({'code': 400, 'msg': '验证失败'})
except User.DoesNotExist as e:
return JsonResponse({'code':200, 'msg':'验证成功'})

进行后续步骤前,我们先验证是否能成功连接到数据库并从中读取数据:

  1. 在Terminal中输入python [manage.py](http://manage.py) shell 进入python环境
  2. 输入from system.models import User
  3. 输入User.objects.get(user_name='abc123'),随便输入一个数据库中有的用户名进行测试

返回如下内容说明连接成功:

1
2
User.objects.get(user_name = 'abc123')
<User: User object (1)>

这里有可能会出现pymysql.err.OperationalError: (1054, "Unknown column '[user.id](http://user.id/)' in 'field list'")报错。

这是因为Django默认所连接的数据表中有一个表名.id字段作为外键,最简便的解决方法就是在表设计时手动添加id字段。

下面开始在login.html中进行修改

首先在文件头加载静态资源:

1
{% load static %}

接着在用户名的check函数中进行如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//验证注册合法性
functioncheck_username() {
user_name =$('#username_reg').val();//$是getelementbyid的一种简便写法
if($.trim(user_name)==''||$.trim(user_name)==null){
$('#notice').html('用户名不能为空');
return false;
}
else{
$('#notice').html('');
flag = true;
$.ajax({
'type': 'POST',
'url': '{% url 'system:unique' %}',
'data': {
'csrfmiddlewaretoken': $.cookie('csrftoken'),
'info': user_name,
'check_type': 'username'
},
'dataType': 'json',
'success': function (result) {
if(result.code==400){
flag = false;
$('#notice').html('该用户名已存在!');
}
},
'error': function (result) {
console.log(result);
}
})
return flag;
}
}

注意'csrfmiddlewaretoken': $.cookie('csrftoken')用到了cookie,所以需要引入jquery.cookie资源:

1
<script type="text/javascript" src="../static/js/jquery.cookie.js"></script>

同时需要在文件头声明{% csrf_token %}

此外还需要在system应用下的urls.py文件进行相应的配置:

1
2
3
4
urlpatterns = [
path('login/', views.login, name='login'),
path('unique/', views.unique, name='unique'),
]

这样一来,当完成用户名输入后,应用就会在后台数据库查询用户名是否存在并返回相应的提示:

邮箱的check函数也可以进行同样的修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
functioncheck_email() {
email =$('#email_reg').val();
var reg = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
if($.trim(email)==''||$.trim(email)==null){
$('#notice').html('邮箱不能为空');
return false;
}
else if(!reg.test(email)){
$('#notice').html('请输入正确格式的邮箱');
return false;
}
else{
$('#notice').html('');
flag = true;
$.ajax({
'type': 'POST',
'url': '{% url 'system:unique' %}',
'data': {
'csrfmiddlewaretoken': $.cookie('csrftoken'),
'info': email,
'check_type': 'email'
},
'dataType': 'json',
'success': function (result) {
if(result.code==400){
flag = false;
$('#notice').html('该邮箱已存在!');
}
},
'error': function (result) {
console.log(result);
}
})
return flag;
}
}

注册按钮事件

检查完合法性与唯一性后,用户点击按钮触发注册事件,前端将用户输入的信息发送到服务器,服务器将这些信息写入后端数据库。实现的代码逻辑与上一步类似。

首先在views.py文件定义注册函数:

1
2
3
4
5
6
7
8
@require_POST
def register(request):
#接收参数
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
User.objects.create(user_name=username, password=password, email=email)
return JsonResponse({'code':200,'msg':'注册成功!'})

接着在login.html中定义按钮触发事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//按钮点击后注册
$('#register_btn').on('click', function () {
var flag =check_username();
if(!flag){
return;
}
var flag =check_email();
if(!flag){
return;
}
var flag =check_password();
if(!flag){
return;
}
var flag =check_confirm_password();
if(!flag){
return;
}
user_name =$('#username_reg').val();
email =$('#email_reg').val();
password =$('#password_reg').val();
$.ajax({
'type': 'POST',
'url': '{% url 'system:register' %}',
'data': {
'csrfmiddlewaretoken': $.cookie('csrftoken'),
'username': user_name,
'email': email,
'password': password
},
'dataType': 'json',
'success': function (result) {
if(result.code==200){
alert('恭喜你,注册成功');
$('#username_reg').val('');
$('#email_reg').val('');
$('#password_reg').val('');
$('#con_password_reg').val('');
}
},
'error': function (result) {
console.log(result);
}
})
})

配置urls.py文件:

1
2
3
4
5
urlpatterns = [
path('login/', views.login, name='login'),
path('unique/', views.unique, name='unique'),
path('register/', views.register, name='register'),
]

此时,当用户名、邮箱与密码输入正确时,前端会弹窗提示,后台能够成功写入。

登录功能


登录功能的实现逻辑与注册差不多,这里不多加赘述。

views.py中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#跳转到主界面的函数
def layout(request):
return render(request,'layout.html') //layout.html是主界面文件,请自行添加到template文件夹中

@require_POST
def login_check(request):
try:
#接收参数
username = request.POST.get('username')
password = request.POST.get('password')
user = User.objects.get(user_name=username, password=password)
return JsonResponse({'code':200, 'msg':'登录成功!'})
except User.DoesNotExist as e:
return JsonResponse({'code':400, 'msg':'用户名或密码错误!'})

login.html中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*实现登录功能
* 1.像注册一样在输入完成后验证用户名的合法性
* 2.按钮点击事件触发后捕获登录名和密码,发送给服务器,在数据库中进行查询,与数据库中账号密码一致则通过
* 3.通过后跳转至主界面*/
//验证用户名不为空,且在数据库中存在
functioncheck_username_login() {
user_name =$('#username_login').val();//$是getelementbyid的一种简便写法
if($.trim(user_name)==''||$.trim(user_name)==null){
$('#notice_login').html('用户名不能为空');
return false;
}
else{
$('#notice_login').html('');
flag = true;
$.ajax({
'type': 'POST',
'url': '{% url 'system:unique' %}',
'data': {
'csrfmiddlewaretoken': $.cookie('csrftoken'),
'info': user_name,
'check_type': 'username'
},
'dataType': 'json',
'success': function (result) {
if(result.code==200){
flag = false;
$('#notice_login').html('该用户名不存在!');
}
},
'error': function (result) {
console.log(result);
}
})
return flag;
}
}
//用户名输入框焦点丢失事件,验证用户名是否为空,以及用户名是否存在
$('#username_login').on('blur',check_username_login);

$('#login').on('click', function () {
var flag =check_username_login();
if(!flag){
return;
}
user_name =$('#username_login').val();
password =$('#password_login').val();
$.ajax({
'type': 'POST',
'url': '{% url 'system:login_check' %}',
'data': {
'csrfmiddlewaretoken': $.cookie('csrftoken'),
'username': user_name,
'password': password
},
'dataType': 'json',
'success': function (result) {
if(result.code==200){
window.location.href = '/layout/'
}
if(result.code==400){
$('#notice_login').html('用户名或密码错误');
}
}
})
})

urls.py中的代码:

1
2
3
4
5
6
7
urlpatterns = [
path('login/', views.login, name='login'),
path('unique/', views.unique, name='unique'),
path('register/', views.register, name='register'),
path('layout/', views.layout, name='layout'),
path('login_check/', views.login_check, name='login_check')
]

至此已经能够实现注册-登录成功后跳转到主界面的功能。