Python+Django+Vue实现登录注册功能

1. 项目主要页面介绍

1.首页

在这里插入图片描述

2. 注册

在这里插入图片描述

3.登录

在这里插入图片描述

2. 项目开发模式

开发模式 前后端不分离
后端框架 Django + Jinja2模板引擎
前端框架 Vue.js

3. 准备项目代码仓库

1.源码托管网站

1、码云(https://gitee.com/)
2、创建源码远程仓库:website
3、克隆项目代码仓库 新建文件夹 下载git  https://git-scm.com/download/win
按默认方式安装。克隆项目:git clone https://gitee.com/lgc1286191951/website.git

2.创建项目工程

1.进入本地项目仓库

$ cd website
2.创建美多商城虚拟环境,安装Django框架
$ mkvirtualenv -p python3 website
$ pip install django
3.创建Django工程
$ django-admin startproject website
创建工程完成后:运行程序,测试结果。

4.配置MySQL数据库

1. 新建MySQL数据库

1.新建MySQL数据库:test
$ create database meiduo charset=utf8;
2.新建MySQL用户

$ create user test identified by ‘123456’;

2. 配置MySQL数据库

DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’, # 数据库引擎
‘HOST’: ‘127.0.0.1’, # 数据库主机
‘PORT’: 3306, # 数据库端口
‘USER’: ‘root’, # 数据库用户名root
‘PASSWORD’: ‘123456’, # 数据库用户密码
‘NAME’: ‘test’ # 数据库名字
},
}
可能出现的错误

Error loading MySQLdb module: No module named ‘MySQLdb’.
出现错误的原因:

Django中操作MySQL数据库需要驱动程序MySQLdb
目前项目虚拟环境中没有驱动程序MySQLdb
解决办法:

安装PyMySQL扩展包
因为MySQLdb只适用于Python2.x的版本,Python3.x的版本中使用PyMySQL替代MySQLdb

3. 安装PyMySQL扩展包

1.安装驱动程序
在windows下安装Mysql
$ pip install PyMySQL
2.在工程同名子目录的__init__.py文件中,添加如下代码:

from pymysql import install_as_MySQLdb

install_as_MySQLdb()
配置完成后:运行程序,测试结果。

5.配置Redis数据库

1. 安装django-redis扩展包

1.安装django-redis扩展包
在windows下安装redis
$ pip install django-redis
2.django-redis使用说明文档
点击进入文档

2. 配置Redis数据库

CACHES = {
“default”: { # 默认
“BACKEND”: “django_redis.cache.RedisCache”,
“LOCATION”: “redis://127.0.0.1:6379/0”,
“OPTIONS”: {
“CLIENT_CLASS”: “django_redis.client.DefaultClient”,
}
},
“session”: { # session
“BACKEND”: “django_redis.cache.RedisCache”,
“LOCATION”: “redis://127.0.0.1:6379/1”,
“OPTIONS”: {
“CLIENT_CLASS”: “django_redis.client.DefaultClient”,
}
},
“verify_code”: { # 验证码
“BACKEND”: “django_redis.cache.RedisCache”,
“LOCATION”: “redis://127.0.0.1:6379/2”,
“OPTIONS”: {
“CLIENT_CLASS”: “django_redis.client.DefaultClient”,
}
},
}
SESSION_ENGINE = “django.contrib.sessions.backends.cache”
SESSION_CACHE_ALIAS = “session”
default:

默认的Redis配置项,采用0号Redis库。
session:

状态保持的Redis配置项,采用1号Redis库。
SESSION_ENGINE

验证码的Redis配置项,采用2号Redis库
verify_code

修改session存储机制使用Redis保存。
SESSION_CACHE_ALIAS:

使用名为"session"的Redis配置项存储session数据。
配置完成后:运行程序,测试结果。

6.配置前端静态文件

1. 准备静态文件

在这里插入图片描述
在这里插入图片描述

2. 指定静态文件加载路径

STATIC_URL = ‘/static/’
配置静态文件加载路径
STATICFILES_DIRS = [os.path.join(BASE_DIR, ‘static’)]
在这里插入图片描述
配置完成后:运行程序,测试结果。

http://127.0.0.1:8000/static/images/test.png

7.创建用户模块子应用

1. 创建用户模块子应用

1.准备apps包,用于管理所有应用
在这里插入图片描述
2.在apps包下创建应用users
$ cd ~/projects/meiduo_project/meiduo_mall/meiduo_mall/apps
$ python …/…/manage.py startapp users
在这里插入图片描述

2. 查看项目导包路径

重要提示:

若要知道如何导入users应用并完成注册,需要知道项目导包路径
在这里插入图片描述
已知导包路径

website/website
已知 'users’应用所在目录
website_project/website/website/apps/users
得到导入’users’应用的导包路路径是website/apps/user

3. 注册用户模块子应用

用Pycharm开发时,把apps设置为资源路径在这里插入图片描述在这里插入图片描述

8.展示用户注册页面

1. 准备用户注册模板文件

在这里插入图片描述
加载页面静态文件
在这里插入图片描述

2. 定义用户注册视图

class RegisterView(View):
“”“用户注册”""

def get(self, request):
    """
    提供注册界面
    :param request: 请求对象
    :return: 注册界面
    """
    return render(request, 'register.html')
  1. 定义用户注册路由
    1.总路由

urlpatterns = [
# users
url(r’^’, include(‘users.urls’, namespace=‘users’)),
]
2.子路由

urlpatterns = [
# 注册
url(r’^register/$’, views.RegisterView.as_view(), name=‘register’),
]

9.定义用户模型类

1. Django默认用户认证系统

Django自带用户认证系统
它处理用户账号、组、权限以及基于cookie的用户会话。
Django认证系统位置
django.contrib.auth包含认证框架的核心和默认的模型。
django.contrib.contenttypes是Django内容类型系统,它允许权限与你创建的模型关联。
Django认证系统同时处理认证和授权
认证:验证一个用户是否它声称的那个人,可用于账号登录。
授权:授权决定一个通过了认证的用户被允许做什么。
Django认证系统包含的内容
用户:用户模型类、用户认证。
权限:标识一个用户是否可以做一个特定的任务,MIS系统常用到。
组:对多个具有相同权限的用户进行统一管理,MIS系统常用到。
密码:一个可配置的密码哈希系统,设置密码、密码校验。

2. Django默认用户模型类

Django认证系统中提供了用户模型类User保存用户的数据。
User对象是认证系统的核心。
Django认证系统用户模型类位置

django.contrib.auth.models.User
在这里插入图片描述

父类AbstractUser介绍

User对象基本属性
创建用户(注册用户)必选: username、password
创建用户(注册用户)可选:email、first_name、last_name、last_login、date_joined、is_active 、is_staff、is_superuse
判断用户是否通过认证(是否登录):is_authenticated
创建用户(注册用户)的方法
user = User.objects.create_user(username, email, password, **extra_fields)
用户认证(用户登录)的方法
from django.contrib.auth import authenticate
user = authenticate(username=username, password=password, **kwargs)
处理密码的方法
设置密码:set_password(raw_password)
校验密码:check_password(raw_password)
3. 自定义用户模型类
思考:为什么要自定义用户模型类?

但是Django默认用户模型类中没有mobile字段,所以要自定义用户模型类。
如何自定义用户模型类?
Django默认用户模型类的文档
继承自AbstractUser(可通过阅读Django默认用户模型类的源码得知) 。
新增mobile字段。
from django.db import models
from django.contrib.auth.models import AbstractUser

Create your models here.

class User(AbstractUser):
“”“自定义用户模型类”""
mobile = models.CharField(max_length=11, unique=True, verbose_name=‘手机号’)

class Meta:
    db_table = 'tb_users'
    verbose_name = '用户'
    verbose_name_plural = verbose_name

def __str__(self):
    return self.username
  1. 知识要点
    Django自带用户认证系统,核心就是User对象,并封装了一系列可用的方法和属性。
    Django用户认证系统包含了一系列对用户的操作,比如:模型类,认证,权限,分组,密码处理等。
    Django用户认证系统中的用户模型类可以自定义,继承自AbstractUser。

10.迁移用户模型类

1. 指定用户模型类

思考:为什么Django默认用户模型类是User?

阅读源代码:‘django.conf.global_settings’
AUTH_USER_MODEL = ‘auth.User’
结论:

Django用户模型类是通过全局配置项 AUTH_USER_MODEL 决定的
配置规则:
在settings.py下进行配置
AUTH_USER_MODEL = ‘应用名.模型类名’
指定本项目用户模型类
AUTH_USER_MODEL = ‘users.User’

2. 迁移用户模型类

1.创建迁移文件

python manage.py makemigrations
在这里插入图片描述

2.执行迁移文件

python manage.py migrate
在这里插入图片描述

11.用户注册业务实现

1. 设计接口基本思路

对于接口的设计,我们要根据具体的业务逻辑,设计出适合业务逻辑的接口。
设计接口的思路:
分析要实现的业务逻辑:
明确在这个业务中涉及到几个相关子业务。
将每个子业务当做一个接口来设计。
分析接口的功能任务,明确接口的访问方式与返回数据:
请求方法(如GET、POST、PUT、DELETE等)。
请求地址。
请求参数(如路径参数、查询字符串、表单、JSON等)。
响应数据(如HTML、JSON等)。

2. 用户注册接口设计

1.请求方式

选项 方案
请求方法 POST
请求地址 /register/
2.请求参数:表单参数

参数名 类型 是否必传 说明
username string 是 用户名
password string 是 密码
password2 string 是 确认密码
mobile string 是 手机号
allow string 是 是否同意用户协议
3.响应结果:HTML

register.html
响应结果 响应内容
注册失败 响应错误提示
注册成功 重定向到首页

3. 用户注册接口定义

1.注册视图

class RegisterView(View):
“”“用户注册”""

def get(self, request):
    """
    提供注册界面
    :param request: 请求对象
    :return: 注册界面
    """
    return render(request, 'register.html')

def post(self, request):
    """
    实现用户注册
    :param request: 请求对象
    :return: 注册结果
    """
    pass

2.总路由

urlpatterns = [
# users
url(r’^’, include(‘users.urls’, namespace=‘users’)),
]
3.子路由

urlpatterns = [
# 注册
url(r’^register/$’, views.RegisterView.as_view(), name=‘register’),
]

12.用户注册前端逻辑

为了学会使用Vue.js的双向绑定实现用户的交互和页面局部刷新效果。

1. 用户注册页面绑定Vue数据

绑定内容:变量、事件、错误提示等

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <link rel="icon" href="../static/image/favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" type="text/css" href="../static/css/main.css">
    <link rel="stylesheet" type="text/css" href="../static/css/reset.css">
    <script src="../static/js/jquery-1.12.4.min.js"></script>
    <script type="text/javascript" src="../static/js/vue-2.5.16.js"></script>
    <script type="text/javascript" src="../static/js/axios-0.18.0.min.js"></script>

</head>
<body class="body_1">
    	<div class="register_con">
            <div class="l_con fl">
            <a class="reg_logo"><img src="../static/image/test.png"></a>
                <div class="reg_slogan">注册即是  ·  巅峰</div>
                <div class="reg_banner"></div>
            </div>
            <div class="r_con fr">
			    <div class="reg_title clearfix">
				<h1>用户注册</h1>
				<a href="/login/">登录</a>
			    </div>
                <div class="reg_form clearfix" id="app" v-cloak>
				<form method="post" @submit="on_submit">
{#                    {% csrf_token %}#}
                    {{ csrf_input }}
				<ul>
					<li>
						<label>用户名:</label>
						<input type="text" name="user_name" id="user_name" v-model="username" @blur="check_username">
						<span class="error_tip" v-show="error_name">[[ error_name_message ]]</span>
					</li>
					<li>
						<label>密码:</label>
						<input type="password" name="pwd" id="pwd" v-model="password" @blur="check_pwd">
						<span class="error_tip" v-show="error_password">[[ error_password_message ]]</span>
					</li>
					<li>
						<label>确认密码:</label>
						<input type="password" name="cpwd" id="cpwd" v-model="password2" @blur="check_cpwd">
						<span class="error_tip" v-show="error_check_password">[[ error_password2_message ]]</span>
					</li>
					<li>
						<label>手机号:</label>
						<input type="text" name="phone" id="phone" v-model="mobile" @blur="check_phone">
						<span class="error_tip" v-show="error_phone">[[ error_phone_message ]]</span>
					</li>
                    <li>
						<label>图形验证:</label>
						<input type="text" name="image_code" id="pic_code" class="msg_input" v-model="image_code"
                               @blur="send_check_image_code">
                        <img :src="image_code_url" alt="图形验证码" class="pic_code" @click="generate_image_code">
                        <span class="error_tip3" v-show="error_image_code">[[ error_image_code_message ]]</span>

					</li>
					<li class="agreement">
						<input type="checkbox" name="allow" id="allow" checked="checked" v-model="allow" @click="click_allow">
						<label>同意”用户使用协议“</label>
                        <span class="error_tip" v-show="error_allow">[[ error_allow_message ]]</span>
                        {% if register_errmsg %}
                            <span class="error_tip3">{{ register_errmsg }}</span>
                        {% endif %}
					</li>
					<li class="reg_sub">
						<input type="submit" value="注 册">
					</li>
				</ul>
				</form>
			</div>

            </div>
		</div>
        <script type="text/javascript" src="../static/js/register.js"></script>
</body>
</html>
var vm = new Vue({
    el: '#app',
    // 修改Vue变量的读取语法,避免和django模板语法冲突
    delimiters: ['[[', ']]'],
    data: {
        host: "http://127.0.0.1:8000",
        error_name: false,
        error_password: false,
        error_check_password: false,
        error_phone: false,
        error_image_code: false,
        error_allow: false,
        error_name_message: '请输入5-20个字符的用户',
        error_password_message: '请输入8-20位的密码',
        error_password2_message: '两次输入的密码不一致',
        error_phone_message: '请输入正确的手机号码',
        error_image_code_message: '请填写图形验证码',
        error_allow_message: '请勾选用户协议',
        uuid: '',
        image_code_url: '',
        sending_flag: false,
        username: '',
        password: '',
        password2: '',
        mobile: '',
        image_code: '',
        allow: true
    },
    mounted: function () {
        // 向服务器获取图片验证码
        this.generate_image_code();
    },
    methods: {
        generateUUID: function () {
            var d = new Date().getTime();
            if (window.performance && typeof window.performance.now === "function") {
                d += performance.now(); //use high-precision timer if available
            }
            var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                var r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
            });
            return uuid;
        },
        // 生成一个图片验证码的编号,并设置页面中图片验证码img标签的src属性
        generate_image_code: function () {
            // 生成一个编号 : 严格一点的使用uuid保证编号唯一, 不是很严谨的情况下,也可以使用时间戳
            this.uuid = this.generateUUID();
            // 设置页面中图片验证码img标签的src属性
            this.image_code_url = this.host + "/image_codes/" + this.uuid + "/";
            console.log(this.image_code_url);
        },
        // 检查用户名
        check_username: function () {
            var re = /^[a-zA-Z0-9_-]{5,20}$/;
            if (re.test(this.username)) {
                this.error_name = false;
            } else {
                this.error_name_message = '请输入5-20个字符的用户名';
                this.error_name = true;
            }
            // 检查重名
            if (this.error_name == false) {
                var url = this.host + '/usernames/' + this.username + '/count/';
                axios.get(url, {
                    responseType: 'json'
                })
                    .then(response => {
                        if (response.data.count > 0) {
                            this.error_name_message = '用户名已存在';
                            this.error_name = true;
                        } else {
                            this.error_name = false;
                        }
                    })
                    .catch(error => {
                        console.log(error.response);


                    })
            }
        },
        // 检查密码
        check_pwd: function () {
            var re = /^[0-9A-Za-z]{8,20}$/;
            if (re.test(this.password)) {
                this.error_password = false;
            } else {
                this.error_password = true;
            }
        },
        // 确认密码
        check_cpwd: function () {
            if (this.password != this.password2) {
                this.error_check_password = true;
            } else {
                this.error_check_password = false;
            }
        },
        // 检查手机号
        check_phone: function () {
            var re = /^1[3-9]\d{9}$/;
            if (re.test(this.mobile)) {
                this.error_phone = false;
            } else {
                this.error_phone_message = '您输入的手机号格式不正确';
                this.error_phone = true;
            }
            if (this.error_phone == false) {
                var url = this.host + '/mobiles/' + this.mobile + '/count/';
                axios.get(url, {
                    responseType: 'json'
                })
                    .then(response => {
                        if (response.data.count > 0) {
                            this.error_phone_message = '手机号已存在';
                            this.error_phone = true;
                        } else {
                            this.error_phone = false;
                        }
                    })
                    .catch(error => {
                        console.log(error.response);
                    })
            }
        },
        // 检查图片验证码
        check_image_code: function () {
            if (!this.image_code) {
                this.error_image_code_message = '请填写图片验证码';
                this.error_image_code = true;

            } else {
                this.error_image_code = false;
            }

        },
        // 检查是否勾选协议
        check_allow: function () {
            if (!this.allow) {
                this.error_allow = true;
            } else {
                this.error_allow = false;
            }
        },
        click_allow: function () {
            this.allow = !this.allow
            this.check_allow()
        },
        // // 发送手机短信验证码
        send_check_image_code: function () {
            this.check_image_code();
            var url = this.host +'/sms_code/'+ this.mobile + '/?image_code=' + this.image_code + '&uuid=' + this.uuid;
                axios.get(url, {
                    responseType: 'json'
                })
                    .then(response => {
                        if (response.data.code == '0') {
                            this.error_image_code = false;
                            console.log("res_success");
                        }else {
                            if (response.data.code == '4001') {
                                this.error_image_code_message = response.data.errmsg;
                                this.error_image_code = true;
                            } else { // 4002
                                this.error_image_code = true;
                                this.error_image_code_message = response.data.errmsg;
                            }
                        }

                    })
                    .catch(error => {
                        console.log(error.response);
                    })
        },
        // 表单提交
        on_submit() {
            this.check_username();
            this.check_pwd();
            this.check_cpwd();
            this.check_allow();

            if (this.error_name == true || this.error_password == true || this.error_check_password == true
                || this.error_phone == true || this.error_allow == true || this.error_image_code == true) {
                // 不满足注册条件:禁用表单
                window.event.returnValue = false;
            }
        }
    }
});


Vue绑定页面的套路
导入Vue.js库和ajax请求的库
准备js文件
html页面绑定变量、事件等
js文件定义变量、事件等
错误提示
如果错误提示信息是固定的,可以把错误提示信息写死,再通过v-show控制是否展示
如果错误提示信息不是固定的,可以使用绑定的变量动态的展示错误提示信息,再通过v-show控制是否展示
修改Vue变量的读取语法,避免和Django模板语法冲突
delimiters: [’[[’, ‘]]’]
后续的页面中如果有类似的交互和刷新效果,也可按照此套路实现

13.状态保持

说明:

如果需求是注册成功后即表示用户登入成功,那么此时可以在注册成功后实现状态保持
如果需求是注册成功后不表示用户登入成功,那么此时不用在注册成功后实现状态保持
美多商城的需求是:注册成功后即表示用户登入成功

  1. login()方法介绍
    用户登入本质:
    状态保持
    将通过认证的用户的唯一标识信息(比如:用户ID)写入到当前浏览器的 cookie 和服务端的 session 中。
    login()方法:
    Django用户认证系统提供了login()方法。
    封装了写入session的操作,帮助我们快速登入一个用户,并实现状态保持。
    login()位置:

django.contrib.auth.init.py文件中。

login(request, user, backend=None)
状态保持 session 数据存储的位置:Redis数据库的1号库
SESSION_ENGINE = “django.contrib.sessions.backends.cache”
SESSION_CACHE_ALIAS = “session”
2. login()方法登入用户
#保存注册数据
try:
user = User.objects.create_user(username=username, password=password, mobile=mobile)
except DatabaseError:
return render(request, ‘register.html’, {‘register_errmsg’: ‘注册失败’})

#登入用户,实现状态保持
login(request, user)

响应注册结果
return redirect(reverse(‘contents:index’))
3. 查看状态保持结果
在这里插入图片描述

14. 用户名重复注册接口设计和定义

1.请求方式

选项 方案
请求方法 GET
请求地址 /usernames/(?P[a-zA-Z0-9_-]{5,20})/count/
2.请求参数:路径参数

参数名 类型 是否必传 说明
username string 是 用户名
3.响应结果:JSON

响应结果 响应内容
code 状态码
errmsg 错误信息
count 记录该用户名的个数
3. 用户名重复注册后端逻辑
class UsernameCountView(View):
“”“判断用户名是否重复注册”""

def get(self, request, username):
    """
    :param request: 请求对象
    :param username: 用户名
    :return: JSON
    """
    count = User.objects.filter(username=username).count()
    return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})
  1. 用户名重复注册前端逻辑
    if (this.error_name == false) {
    let url = ‘/usernames/’ + this.username + ‘/count/’;
    axios.get(url,{
    responseType: ‘json’
    })
    .then(response => {
    if (response.data.count == 1) {
    this.error_name_message = ‘用户名已存在’;
    this.error_name = true;
    } else {
    this.error_name = false;
    }
    })
    .catch(error => {
    console.log(error.response);
    })
    }
    判断用户名重复注册的核心思想:
    使用用户名查询该用户名对应的记录是否存在,如果存在,表示重复注册了,反之,没有重复注册。
    axios发送异步请求套路:
    处理用户交互
    收集请求参数
    准备请求地址
    发送异步请求
    得到服务器响应
    控制界面展示效果

15. 手机号重复注册接口设计和定义

1.请求方式

选项 方案
请求方法 GET
请求地址 /mobiles/(?P1[3-9]\d{9})/count/
2.请求参数:路径参数

参数名 类型 是否必传 说明
mobile string 是 手机号
3.响应结果:JSON

响应结果 响应内容
code 状态码
errmsg 错误信息
count 记录该用户名的个数
3. 手机号重复注册后端逻辑
class MobileCountView(View):
“”“判断手机号是否重复注册”""

def get(self, request, mobile):
    """
    :param request: 请求对象
    :param mobile: 手机号
    :return: JSON
    """
    count = User.objects.filter(mobile=mobile).count()
    return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})
  1. 手机号重复注册前端逻辑
    if (this.error_mobile == false) {
    let url = ‘/mobiles/’+ this.mobile + ‘/count/’;
    axios.get(url, {
    responseType: ‘json’
    })
    .then(response => {
    if (response.data.count == 1) {
    this.error_mobile_message = ‘手机号已存在’;
    this.error_mobile = true;
    } else {
    this.error_mobile = false;
    }
    })
    .catch(error => {
    console.log(error.response);
    })
    }

16.图形验证码接口设计和定义

1. 图形验证码接口设计

1.请求方式

选项 方案
请求方法 GET
请求地址 image_codes/(?P[\w-]+)/
2.请求参数:路径参数

参数名 类型 是否必传 说明
uuid string 是 唯一编号
3.响应结果:image/jpg

  1. 图形验证码接口定义
    1.图形验证码视图

class ImageCodeView(View):
“”“图形验证码”""

def get(self, request, uuid):
    """
    :param request: 请求对象
    :param uuid: 唯一标识图形验证码所属于的用户
    :return: image/jpg
    """
    pass

2.总路由

#verifications
url(r’^’, include(‘verifications.urls’)),
3.子路由

#图形验证码
url(r’^image_codes/(?P[\w-]+)/$’, views.ImageCodeView.as_view()),

2.图形验证码后端逻辑

  1. 准备captcha扩展包
    提示:captcha扩展包用于后端生成图形验证码

在这里插入图片描述

可能出现的错误
在这里插入图片描述
报错原因:环境中没有Python处理图片的库:PIL

解决办法

安装Python处理图片的库:pip install Pillow
2. 准备Redis数据库
准备Redis的2号库存储验证码数据

“verify_code”: { # 验证码
“BACKEND”: “django_redis.cache.RedisCache”,
“LOCATION”: “redis://127.0.0.1:6379/2”,
“OPTIONS”: {
“CLIENT_CLASS”: “django_redis.client.DefaultClient”,
}
},
3. 图形验证码后端逻辑实现
class ImageCodeView(View):
“”“图形验证码”""

def get(self, request, uuid):
    """
    :param request: 请求对象
    :param uuid: 唯一标识图形验证码所属于的用户
    :return: image/jpg
    """
    # 生成图片验证码
    name, text, image = captcha.generate_captcha()

    # 保存图片验证码
    redis_conn = get_redis_connection('verify_code')
    redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text)

    # 响应图片验证码
    return http.HttpResponse(image, content_type='image/jpg')

3.图形验证码前端逻辑

  1. Vue实现图形验证码展示
    1.register.js

mounted(){
// 生成图形验证码
this.generate_image_code();
},
methods: {
// 生成图形验证码
generate_image_code(){
// 生成UUID。generateUUID() : 封装在common.js文件中,需要提前引入
this.uuid = generateUUID();
// 拼接图形验证码请求地址
this.image_code_url = “/image_codes/” + this.uuid + “/”;
},

}
2.register.html

java
<li>
    <label>图形验证码:</label>
    <input type="text" name="image_code" id="pic_code" class="msg_input">
    <img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
    <span class="error_tip">请填写图形验证码</span>
</li>

3.图形验证码展示和存储效果
在这里插入图片描述

  1. Vue实现图形验证码校验
    1.register.html
<li>
    <label>图形验证码:</label>
    <input type="text" v-model="image_code" @blur="check_image_code" name="image_code" id="pic_code" class="msg_input">
    <img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
    <span class="error_tip" v-show="error_image_code">[[ error_image_code_message ]]</span>
</li>

2.register.js

check_image_code(){
if(!this.image_code) {
this.error_image_code_message = ‘请填写图片验证码’;
this.error_image_code = true;
} else {
this.error_image_code = false;
}
},
3.图形验证码校验效果
在这里插入图片描述

17 用户名登录

1.登录

1.请求方式

选项 方案
请求方法 POST
请求地址 /login/
2.请求参数:表单

参数名 类型 是否必传 说明
username string 是 用户名
password string 是 密码
remembered string 是 是否记住用户
3.响应结果:HTML

字段 说明
登录失败 响应错误提示
登录成功 重定向到首页
3. 用户名登录接口定义
class LoginView(View):
“”“用户名登录”""

def get(self, request):
    """
    提供登录界面
    :param request: 请求对象
    :return: 登录界面
    """
    pass

def post(self, request):
    """
    实现登录逻辑
    :param request: 请求对象
    :return: 登录结果
    """
    pass
  1. 用户名登录后端逻辑
    class LoginView(View):
    “”“用户名登录”""

    def get(self, request):
    “”"
    提供登录界面
    :param request: 请求对象
    :return: 登录界面
    “”"
    return render(request, ‘login.html’)

    def post(self, request):
    “”"
    实现登录逻辑
    “”"
    # 接受参数
    username = request.POST.get(‘username’)
    password = request.POST.get(‘password’)
    remembered = request.POST.get(‘r’)

     # 认证登录用户
     user = authenticate(username=username, password=password)
     if user is None:
         return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})
    
     # 实现状态保持
     login(request, user)
     # 设置状态保持的周期
     if remembered != 'on':
         # 没有记住用户:浏览器会话结束就过期, 默认是两周
         request.session.set_expiry(0)
    
     # 响应登录结果
     return redirect(reverse('contents:index'))
    

登录的核心思想:认证和状态保持
通过用户的认证,确定该登录用户是美多商场的注册用户。
通过状态保持缓存用户的唯一标识信息,用于后续是否登录的判断。

2.退出登录

  1. logout()方法介绍
    退出登录:

回顾登录:将通过认证的用户的唯一标识信息,写入到当前session会话中
退出登录:正好和登录相反(清理session会话信息)
logout()方法:

Django用户认证系统提供了logout()方法
封装了清理session的操作,帮助我们快速实现登出一个用户
logout()位置:

django.contrib.auth.init.py文件中
logout(request)
2. logout()方法使用
class LogoutView(View):
“”“退出登录”""

def get(self, request):
    """实现退出登录逻辑"""
    # 清理session
    logout(request)
    # 退出登录,重定向到登录页
    response = redirect(reverse('users:login'))
    # 退出登录时清除cookie中的username
    response.delete_cookie('username')

    return response

退出登录的核心思想就是清理登录时缓存的状态保持信息。
由于首页中用户名是从cookie中读取的。所以退出登录时,需要将cookie中用户名清除。

3.首页展示

Vue渲染首页用户名
1.index.html

<div v-if="username" class="login_btn fl">
    欢迎您:<em>[[ username ]]</em>
    <span>|</span>
    <a href="#">退出</a>
</div>
<div v-else class="login_btn fl">
    <a href="login.html">登录</a>
    <span>|</span>
    <a href="register.html">注册</a>
</div>

2.index.js

mounted(){
// 获取cookie中的用户名
this.username = getCookie(‘username’);
},
在这里插入图片描述

完成登录展示

猜你喜欢

转载自blog.csdn.net/QQ128619/article/details/106185767