实现用户注册,用户名邮箱合法性检查,用户名密码验证,登录的功能。涉及前端的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') ]
|
至此已经能够实现注册-登录成功后跳转到主界面的功能。