#前言:
在最近十天我会用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要对应。后续小编会更新项目其它内容,欢迎大家关注,同时也欢迎大家评论指正。