十日Python项目——第三日(用户中心——邮箱验证、修改密码)

#前言:

在最近十天我会用Python做一个购物类项目,会用到Django+Mysql+Redis+Vue等。

今天是第三天,主要负责撰写用户中心部分,以及优化登录部分。若是有不懂大家可以先阅读我的前两篇博客以能够顺承。博客:十日Python项目——第二天(用户登录)-CSDN博客

十日Python项目——第一天(用户注册)-CSDN博客

若是大家基础有不懂的,小编前面已经关于Django博客都更新完了,大家可以自行查看。若是有需要更改的地方欢迎大家指正,同时也欢迎大家关注点赞收藏等待后续,小编会尽力更新优质博客。

在此我会直接继承上一篇博客继续往下写。

九、用户中心:

首先用户中心我们要干什么:

这是我关于用户中心的一个简单设计,所以如图所示,我们需要做到能将用户的数据响应到页面,以及添加验证邮箱,修改密码等操作,今天博客我会讲解关于邮箱和修改密码操作。

1、响应用户中心:

注意:包括响应前端页面以及分发路由。

# 用户中心
path('info/' , views.UserInfoView.as_view() , name='info'),class UserInfoView(View):'''用户中心'''def get(self , request):return render(request , 'user_center_info.html')

2、判断登录状态:

因为我们要在用户中心进行各种操作首先我们得处于已经登录的状态。

实现 Django 用户认证提供 :LoginRequiredMixin 进行用户登录判断,实现这个功能直接继承该类即可。

from django.contrib.auth.mixins import LoginRequiredMixin #判断登陆状态要继承的类
class UserInfoView(LoginRequiredMixin,View):#先判断的登录再实现视图你,所以View继承在后面'''用户中心'''def get(self,request):return render(request,'user_center_info.html',context=context)#context=context就是把它也要响应到前端页面

注意也就是类继承认证模块。

在配置文件中重新定义认证登录重定向 url:

# 配置项目认证登录的重定向
LOGIN_URL = '/login/'

3、修改登录视图:

这里就是若是我们一开始没有登录,那么我们访问需要登录状态才能访问的页面才能访问的页面我们会重定向到登录页面,当我们登录后会继续重定向到刚刚我们要访问的页面。

在登录的post请求中添加:

next = request.GET.get('next')if next:# next 有值 , 重定向到指定的 urlresponse = redirect(next)else:# 响应首页中response = redirect('index')

上面代码的意思就是先获取登录的状态若是没登录返回首页,登录则返回要访问的页面。

所以此时的完整登录代码:

class LoginView(View):'''用户登录'''def get(self,request):return render(request,'login.html')def post(self,request):login_form=LoginForm(request.POST)if login_form.is_valid():username=login_form.cleaned_data.get('username')password=login_form.cleaned_data.get('password')remembered=login_form.cleaned_data.get('remembered')if not all([username,password]):#验证数据完整性return HttpResponse('缺少必要的数据')#通过认证模块,不要到数据库直接校验,因为数据是加密的。user=authenticate(username=username,password=password)#判断是否在数据库中获取到用户数据if user is None:return render(request,'login.html',{'account_errmsg':'用户名或者密码错误'})#状态保持login(request,user)#判断用户是否选择记住登录状态:if remembered:request.session.set_expiry(None)#默认记住14天else:request.session.set_expiry(0)#不记住登录状态,登录销毁next = request.GET.get('next')if next:# next 有值 , 重定向到指定的 urlresponse = redirect(next)else:# 响应首页中response = redirect('index')# 将用户名写入到 Cookie 中response.set_cookie('username', user.username, 3600)return responseelse:context={'forms_errmsg':login_form.errors}return render(request,'login.html',context=context)

4、获取用户数据:

获取用户数据也就是我们登陆后页面能显示出我们的用户名手机号等信息。

不是新创建的视图,而是原先视图,加上了获取信息,返回值里面context别忘

class UserInfoView(LoginRequiredMixin , View):'''用户中心'''def get(self , request):# 从 request 中获取用户信息context = {"username" : request.user.username,"mobile" : request.user.mobile,"email" : request.user.email}return render(request , 'user_center_info.html' , context=context)

前端页面响应:

<li><span>用户名:</span>[[ username ]]</li>
<li><span>联系方式:</span>[[ mobile ]]</li>

此时email还是没有信息的,所以我们无法响应。

5、添加邮箱:

首先要在模型数据库里面加上邮箱,其次验证邮箱,最后将邮箱写入数据库。

5.1、模型类中添加邮箱:

也就是多加了个Email,但是要注意,它一定是可以为空的,不然在注册那块过不去,因为我们注册那点没有涉及邮箱。
 

from django.db import models
from django.contrib.auth.models import  AbstractUser
#注意先不迁移(因为要用到继承)
class User(AbstractUser):'''用户数据认证模型类'''mobile=models.CharField(max_length=11,unique=True)email = models.EmailField(blank=True, null=True)  # 允许为空class Meta:db_table='user'

5.2、重写类方法:

验证登录的: LoginRequiredMixin 要求的返回值是 HttpResponse 对象或者其子类对象 , 如果返回的是 json 类型必须重写类方法。

在项目全局的 utils 包中创建一个 view 模块。

from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from utils.response_code import RETCODEclass LoginRequiredJsonMixin(LoginRequiredMixin):def handle_no_permission(self):# 重写方法 , 重新定义这个方法的返回值修改为 json 类型return JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '用户未登录'})

5.3、添加邮箱:

注意此时提交邮箱的方法是put请求。

# 添加邮箱
path('email/' , views.EmailView.as_view()),class EmailView(LoginRequiredJsonMixin , View):'''用户添加邮箱'''def put(self , request):# put 请求的参数放在 request 的请求体中 body 中,是一个以字节的方式传输数据# b'{'email':'123@com'}' ==> '{'email':'123@com'}' ==> {'email':'123@com'}email_dict = json.loads(request.body.decode())email = email_dict.get('email')# 数据校验if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$' , email):return HttpResponseForbidden('邮箱格式不正确')# 保存到数据库中request.user.email = emailrequest.user.save()# 添加成功return JsonResponse({'code':RETCODE.OK , 'errmsg':"ok"})

6、邮箱验证:

这里我们以网易邮箱为例

让 Django 发送邮件 , 是无法直接发送,需要借助 SMTP 服务器进行中转需要在 Django 项目的配置文件中配置邮箱需要的信息。

6.1、配置邮箱:

配置邮箱是为了我们能够验证发送邮箱等功能。

在设置中打开 POP3/SMTP/IMAP:

开启 IMAP/SMTP 和 POP3/SMTP
获取授权码(代码中会用到)

在settings文件下配置信息:

EMAIL_HOST_PASSWORD也就是上面我们提及的授权码。

# 发送邮件的配置参数
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 	# 指定邮件后端
EMAIL_HOST = 'smtp.163.com'	 	# 发邮件主机(网易邮箱)
EMAIL_PORT = 25		# 发邮件的端口
EMAIL_HOST_USER = '15609448850@163.com'  # 授权邮箱
EMAIL_HOST_PASSWORD = ''		# 邮箱授权时获取的密码,非登录邮箱的密码
EMAIL_FROM = 'AC-<15609448850@163.com>'		# 发件人抬头# 设置邮箱的激活连接
EMAIL_VERIFY_URL = 'http://127.0.0.1:8000/verification/'#端口号修改了的话自己别忘记修改

6.2、测试发送邮箱:

此时在tests文件下:

直接运行tests.py文件就可以做测试文件来发送数据消息。

from django.test import TestCase# Create your tests here.
if __name__=='__main__':import osos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ShopSystem.settings')import djangodjango.setup()from django.core.mail import send_mail# 邮件标题subject = '发送邮件 test'# 邮件正文(普通的没有格式的文本文件,字符串)message = '发送测试邮件'# 邮件正文(文件可以带有渲染格式)html_message = '<h1>发送测试邮件</h1>'# 发件人抬头from_email = 'AC-<15609448850@163.com>'# 收件人邮箱(列表格式)recipient_list = ['15609448850@163.com', ]send_mail(subject, message, from_email, recipient_list, html_message=html_message)

6.3、制作邮箱激活链接:

因为发送邮箱我们要验证的话会有激活链接:

首先安装好模块,最好是我指定的这个版本。

pip install itsdangerous==1.1.0

制作邮箱的激活连接 , 在 users 应用下的 utils中操作:

导入加密模块:

from itsdangerous import TimedJSONWebSignatureSerializer as TJWSS
def generate_verify_email_url(user):'''生成邮箱激活连接:param user: 用户数据:return: 返回加密的连接'''# 调用加密的方法s = TJWSS(SECRET_KEY , 600)# 获取用户的基本数据data = {'user_id':user.id , 'email':user.email}token = s.dumps(data)# http://127.0.0.1:8001/verification/?return EMAIL_VERIFY_URL+'?token='+ token.decode()

6.4、发送邮箱激活验证连接:

在用户保存邮箱之后,就发送邮箱激活验证连接。

class EmailView(View):'''用户添加邮箱'''def put(self , request):# put 请求的参数放在 request 的请求体中 body 中,是一个以字节的方式传输数据# b'{'email':'123@com'}' ==> '{'email':'123@com'}' ==> {'email':'123@com'}email_dict = json.loads(request.body.decode())email = email_dict.get('email')# 数据校验if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$' , email):return HttpResponseForbidden('邮箱格式不正确')# 保存到数据库中request.user.email = emailrequest.user.save()#调用生成邮箱的加密验证链接的方法verify_url=generate_verify_email_url(request.user)#发送验证邮箱# 邮件标题subject = '龙哥发的邮箱验证'# 邮件正文(文件可以带有渲染格式)html_message = f'<p>您的邮箱{email},点击链接进行验证激活邮箱</p>'\f'<p><a href="{verify_url}">{verify_url}</p>'# 收件人邮箱(列表格式)recipient_list = [email, ]send_mail(subject,'' ,from_email=settings.EMAIL_FROM,recipient_list=recipient_list, html_message=html_message)# 添加成功return JsonResponse({'code':RETCODE.OK , 'errmsg':"ok"})

6.5、邮箱验证:

验证要验证两个点:

1、数据库中是否已经存在该邮箱。

2、发送的邮箱链接是否和我们填写的验证上。

6.5.1、验证是否已经存在:

在 Django 中实现邮箱的数据验证 , 需要接收用书邮箱链接发送过来的参数

进行对参数解码 、校验。

同样是在utils文件:

def check_verify_email_token(token):'''校验邮箱链接中的参数:param token: 用户的加密邮箱链接:return: 用户数据 ; 数据不对返回 None'''s = TJWSS(SECRET_KEY, 600)data = s.loads(token)user_id = data.get('user_id')email = data.get('email')# 从数据库中查询是否有该用户try:user = User.objects.get(id=user_id , email=email)except Exception:return Noneelse:return user
6.5.1、链接验证:

实现验证邮箱视图

关于token都是与Ajax的参数对应的。

# 验证邮箱
path('verification/' , views.VerifyEmailView.as_view()),class VerifyEmailView(View):'''邮箱验证'''def get(self , request):token = request.GET.get('token')if not token:return HttpResponseForbidden('缺少必要的数据')# 调用解码验证方法user = check_verify_email_token(token)if not user:return HttpResponseForbidden('邮箱验证码失败')# 判断用户是否以验证邮箱if user.is_active == 0:# 用户没有验证邮箱user.is_active = 1user.save()else:return HttpResponseForbidden('用户以验证邮箱')# 验证成功 , 重定向到用户中心return redirect('/info/')

注意:判断user.is_active是0/1,这是在数据库中自动生成的字段,具体叫什么可以自行上数据库查看,但是参数的判别不会有错。

7、修改密码:

修改密码主要涉及的操作就是:

1、验证旧密码是否正确

2、判断新密码是否合法且一致

3、修改好后要清楚用户的登录状态(也就是前面提到的退出登录),再重定向到登录页面重新登录。

注意:因为他也是验证我们自己提交的数据所以参数名和我们的Ajax名一致。

# 修改密码
path('changepwd/' , views.ChangePasswordView.as_view() , name='changepwd'),class ChangePasswordView(View):'''修改密码'''def get(self , request):return render(request , 'user_center_pass.html')def post(self , request):# 接收用户输入的密码数据old_password = request.POST.get('old_password')new_password = request.POST.get('new_password')new_password2 = request.POST.get('new_password2')# 校验数据 , 数据是否完整if not all([old_password , new_password , new_password2]):return HttpResponseForbidden('缺少必要的数据')# 校验旧密码是否正确if not request.user.check_password(old_password):return render(request , 'user_center_pass.html' , {'origin_password_errmsg':'当前密码不正确'})# 校验新密码中的数据是否合法if not re.match(r'^[0-9a-zA-Z]{6,20}$' , new_password):return render(request , 'user_center_pass.html' , {'change_password_errmsg':'密码格式不正确'})# 校验两次密码是否一致if new_password != new_password2:return render(request, 'user_center_pass.html', {'change_password_errmsg': '两次密码不一致'})# 密码合法 , 将新的密码重新保存request.user.set_password(new_password)request.user.save()# 更新用户的状态保持 , 清理原有的密码数据logout(request)response = redirect('login')response.delete_cookie('username')return response

#总结:
今天的用户中心我们最难点就是邮箱的添加验证同样用到很多方法串联。全局许多东西都是需要前后端对应,尤其与Ajax要对应。后续小编会更新项目其它内容,欢迎大家关注,同时也欢迎大家评论指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/50408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端江湖:从菜鸟到大侠的修炼手册

在这个数字编织的梦幻世界里&#xff0c;前端&#xff0c;这个听起来就带着几分仙气与神秘感的词汇&#xff0c;实则是每一位互联网探险家手中的魔法杖。它不仅连接着代码的冰冷逻辑与用户的炽热情感&#xff0c;更在无数次的点击与滑动间&#xff0c;绘制出一幅幅绚丽多彩的交…

Godot入门 05收集物品

创建新场景&#xff0c;添加Area2D节点&#xff0c;AnimatedSprite2D节点 &#xff0c;CollisionShape2D节点 添加硬币 按F键居中&#xff0c;放大视图。设置动画速度设为10FPS&#xff0c;加载后自动播放&#xff0c;动画循环 碰撞形状设为圆形&#xff0c;修改Area2D节点为Co…

Go语言常见序列化协议全面对比

先说结论 从易用性、性能、内存占用、编码后大小等几个方面综合考虑 ProtoBuf 胜出。 Gob 从性能和 I/O 带宽占用上都和 ProtoBuf 差不多&#xff0c;唯一劣势是编解码时内存占用较多。考虑到不用再写 IDL 带来的易用性&#xff0c;如果整个系统内不存在使用除 Go 以外其他语言…

外卖霸王餐系统推荐,哪家的系统比较稳定呢?

以下是一些较为稳定且有一定用户基础的外卖霸王餐系统&#xff0c;你可以根据自身需求进一步考察和选择&#xff1a; - **饭否霸王餐**&#xff1a;有专门的APP&#xff0c;如在应用宝上其开发商为南京有惠鲸选电子商务有限公司。它覆盖了多个城市&#xff0c;提供美团、饿了么…

巴黎奥运启幕 PLM系统助力中国制造闪耀全球

2024巴黎奥运会将于法国当地时间7月26日在塞纳河畔正式开幕。即将亮相巴黎奥运会赛场的除了中国运动员之外&#xff0c;还有一批批中国制造企业为奥运会设计并制造的体育设备也将惊艳亮相&#xff0c;成为赛场上另一道亮丽的风景线。 在新时代的浪潮中&#xff0c;中国制造业坚…

AlibabaCloudAI

快速体验 Spring Cloud Alibaba AI JDK要求最低17 1.SpringAI Spring AI 旨在简化包含人工智能相关功能的应用程序的开发&#xff0c;避免不必要的复杂性。 Spring AI 的核心是提供抽象&#xff0c;作为开发 AI 应用程序的基础。这些抽象有多种实现方式&#xff0c;只需极少…

三维影像系统PACS源码,图像存储与传输系统,应用于医院中管理医疗设备如CT,MR等产生的医学图像的信息系统

PACS&#xff0c;即图像存储与传输系统&#xff0c;是应用于医院中管理医疗设备如CT&#xff0c;MR等产生的医学图像的信息系统。目标是支持在医院内部所有关于图像的活动&#xff0c;集成了医疗设备&#xff0c;图像存储和分发&#xff0c;数字图像在重要诊断和会诊时的显示&a…

Redis的五种数据类型与命令

目录 引言 一 Redis的特性 二 Redis的安装 三 Redis的优点 四 Redis的五种数据类型与命令 五 Redis的配置文件 引言 Redis是什么&#xff1f; Remote Dictionary Service(远程字典服务器) Redis 是一个开源的(BSD许可)的&#xff0c;C语言编写的&#xff0c;高性能的数…

计算机网络实验-RIP配置与分析

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、相关知识 路由信息协议&#xff08;Routing Information Protocol&#xff0c;RIP&#xff09;是一种基于距离向量&#xff08;Distance-Vector&…

unity2D游戏开发06稳定,材质,碰撞器

稳定性 在操控玩家时,我们会发现玩家移动时,摄像头会有抖动,这是摄像机过度精确造成的。 创建名为RoundCameraPos的C#脚本,用Visual Studio打开 代码 using System.Collections; using System.Collections.Generic; using UnityEngine; using Cinemachine;//导入Cinemac…

rust 初探 -- use

rust 初探 – use Package, Crate, 定义 Module use 关键字 作用&#xff1a;将路径引入到作用域内&#xff0c;其依旧遵循私有性规则&#xff0c;也即只用 pub 的部分引入进来才能使用 use crate::front_of_house::hosting; // 绝对路径 // use front_of_house::hosting; …

【Python机器学习】使用Matplotlib注解绘制树形图

通过数据集可以创建树&#xff0c;但是字典的表示形式非常不易于理解&#xff0c;而且直接绘制图形也比较困难。但是通过Matplotlib库可以绘制树形图。 决策树的主要优点就是直观、易于理解&#xff0c;如果不能将其直观的显示出来&#xff0c;就无法发挥其优势。 Matplotlib…

基于JSP、java、Tomcat三者的项目实战--校园交易网(2)登录,注册功能实现

技术支持&#xff1a;JAVA、JSP 服务器&#xff1a;TOMCAT 7.0.86 编程软件&#xff1a;IntelliJ IDEA 2021.1.3 x64 OK&#xff0c;那我们进入正题&#xff0c;随着前面一篇博客的尚未完结基于JSP、java、Tomcat三者的项目实战--校园交易网&#xff08;2&#xff09;登录功能…

微软蓝屏事件:网络安全的多维挑战与应对策略

一、引言 1. 事件概述&#xff1a;微软蓝屏事件的影响与范围 微软蓝屏事件&#xff0c;这一近期震动全球科技界的重大事件&#xff0c;起因于一次看似平常的软件更新。美国电脑安全技术公司“众击”发布的更新包中隐藏着一个致命的“缺陷”&#xff0c;这个缺陷如同潜伏的病毒…

函数图像是如何画出来的(LiveCharts2)

大火的人工智能本质上就是一些简单的函数的组合&#xff0c;比如f(x)kxb&#xff0c;只是可能不只有x,还会x1&#xff0c;x2&#xff0c;…xn&#xff0c;只是维数不同&#xff0c;当维数很多的时候自然就需要方程组才能求解&#xff0c;维数越多自然需要的算力就越多。于是就有…

简单小案例分析

一、容器和实例关系 <div class"app"><h1>Hello,{{name}}</h1> </div> <div class"app"><h1>Hello,{{name}}</h1> </div><script>//创建Vue实例new Vue({el:".app", //el用于指定当前V…

DBeaver Ultimate 22.1.0 连接数据库(MySQL+Mongo+Clickhouse)

前言 继续书接上文 Docker Compose V2 安装常用数据库MySQLMongo&#xff0c;部署安装好之后我本来是找了一个web端的在线连接数据库的工具&#xff0c;但是使用过程中并不丝滑&#xff0c;最终还是选择了使用 DBeaver &#xff0c;然后发现 mongo 还需要许可&#xff0c;又折…

PyQt5 + selenium,自动票务工具,演唱会门票,学习使用

PyQt5 selenium&#xff1b;在damai工具的基础上加入了UI界面&#xff0c;并将应用做了打包工作&#xff0c;主要是方便不会/不想折腾环境的用户使用&#xff0c;抢票的核心代码来自由于原作者不再维护&#xff0c;自己修改了部分代码。 安装教程 解压安装包到任意位置&…

SpringBoot整合elasticsearch-java

一、依赖 系统使用的是ElasticSearch8.2.0 <dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>8.1.0</version> </dependency> 二、配置 1、yml文件配置 elastics…

Mongodb文档和数组的通配符索引

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第97篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…