实现用户注册,用户名邮箱合法性检查,用户名密码验证,登录的功能。涉及前端的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
 
  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())
  	     class Meta(object):         db_table = 'user'
   | 
 
注意这里字段的类型和长度设定需要与数据库中相一致:
定义视图
修改views.py文件:
1 2 3 4 5 6
   | from django.shortcuts import render
 
 
  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中打开我们的页面,在页面上右键选择「检视」,进入开发者模式。
选中用户名输入框发现定位到如下位置:
说明用户名输入框的id为user,下面我们就可以通过这个id对用户名进行读取。
- 下面实现判断用户名是否为空。
 
该判断应该在用户完成输入,也就是用户先选中用户名输入框,完成输入后再将焦点转向其他位置时进行。这就要用到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();          if($.trim(user_name)==''||$.trim(user_name)==null){             $('#notice').html('用户名不能为空');              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
   | 
 
../表示进入返回上级目录,./表示同级目录
- 对于邮箱,除了判断是否为空外,还要验证邮箱格式是否符合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 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 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)                          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':'验证成功'})
   | 
 
进行后续步骤前,我们先验证是否能成功连接到数据库并从中读取数据:
- 在Terminal中输入
python [manage.py](http://manage.py) shell 进入python环境 
- 输入
from system.models import User 
- 输入
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中进行修改
首先在文件头加载静态资源:
接着在用户名的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(); 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
   | 
 
 
 
  functioncheck_username_login() {     user_name =$('#username_login').val(); 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') ]
   | 
 
至此已经能够实现注册-登录成功后跳转到主界面的功能。