vue父子组件
有两种模式一种是前后端不分离模式、一种是前后端分离的模式:
那就先说一种不分离模式下如何实现的:
开发模式 前后端不分离
后端框架 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’)]
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. 准备用户注册模板文件
加载页面静态文件
class RegisterView(View):
“”“用户注册”""
def get(self, request):
"""
提供注册界面
:param request: 请求对象
:return: 注册界面
"""
return render(request, 'register.html')
- 定义用户注册路由
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
- 认证系统,核心就是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.状态保持
说明:
如果需求是注册成功后即表示用户登入成功,那么此时可以在注册成功后实现状态保持
如果需求是注册成功后不表示用户登入成功,那么此时不用在注册成功后实现状态保持
美多商城的需求是:注册成功后即表示用户登入成功
- 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})
- 用户名重复注册前端逻辑
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})
- 手机号重复注册前端逻辑
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.图形验证码视图
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.图形验证码后端逻辑
- 准备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):
“”“图形验证码”""-
报错原因:环境中没有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): “”“图形验证码”""
3.图形验证码前端逻辑
- 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 - Vue实现图形验证码展示
-
<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.图形验证码展示和存储效果
- Vue实现图形验证码校验
1.register.html
- Vue实现图形验证码校验
-
<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
用户名登录后端逻辑
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.退出登录
- logout()方法介绍
退出登录:
回顾登录:将通过认证的用户的唯一标识信息,写入到当前session会话中
退出登录:正好和登录相反(清理session会话信息)
logout()方法:Django用户认证系统提供了logout()方法
封装了清理session的操作,帮助我们快速实现登出一个用户
logout()位置:django.contrib.auth.init.py文件中
logout(request)
2. logout()方法使用
class LogoutView(View):
“”“退出登录”"" - logout()方法介绍
-
def get(self, request): """实现退出登录逻辑""" # 清理session logout(request) # 退出登录,重定向到登录页 response = redirect(reverse('users:login')) # 退出登录时清除cookie中的username response.delete_cookie('username') return response
退出登录的核心思想就是清理登录时缓存的状态保持信息。
由于首页中用户名是从cookie中读取的。所以退出登录时,需要将cookie中用户名清除。
-