上面咱们的用户登陆的方法是基于函数来作的。本节咱们作一个基于类方法的版本。
要求对类的继承有了解。javascript
基础教程中基本上都是基于函数来作的,其实更推荐基于类来作。基于类能够带来很多好处php
# 基于类实现须要继承的view from django.views.generic.base import View class LoginView(View): # 直接调用get方法免去判断 def get(self, request): # render就是渲染html返回用户 # render三变量: request 模板名称 一个字典写明传给前端的值 return render(request, "login.html", {}) def post(self, request): # 取不到时为空,username,password为前端页面name值 user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") # 成功返回user对象,失败返回null user = authenticate(username=user_name, password=pass_word) # 若是不是null说明验证成功 if user is not None: # login_in 两参数:request, user # 实际是对request写了一部分东西进去,而后在render的时候: # request是要render回去的。这些信息也就随着返回浏览器。完成登陆 login(request, user) # 跳转到首页 user request会被带回到首页 return render(request, "index.html") # 没有成功说明里面的值是None,并再次跳转回主页面 else: return render(request, "login.html", {"msg": "用户名或密码错误! "})
继承的view中的方法。html
django1.9.8 urls中的配置:前端
# 换用类实现 from users.views import LoginView # 基于类方法实现登陆,这里是调用它的方法 url('^login/$', LoginView.as_view(), name="login")
Django2.0.1 urls配置:java
# 基于类方法实现登陆,这里是调用它的方法 path('login/', LoginView.as_view(), name="login")
验证最大长度,是否为空等一系列。python
users下新建forms文件。git
# encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/1/10 0010 04:44' # 引入Django表单 from django import forms # 登陆表单验证 class LoginForm(forms.Form): # 用户名密码不能为空 username = forms.CharField(required=True) password = forms.CharField(required=True, min_length=5)
定义好forms以后咱们来使用它作验证。github
def post(self, request): # 类实例化须要一个字典参数dict:request.POST就是一个QueryDict因此直接传入 # POST中的usernamepassword,会对应到form中 login_form = LoginForm(request.POST) #is_valid判断咱们字段是否有错执行咱们原有逻辑,验证失败跳回login页面 if login_form.is_valid(): # 取不到时为空,username,password为前端页面name值 user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") # 成功返回user对象,失败返回null user = authenticate(username=user_name, password=pass_word) # 若是不是null说明验证成功 if user is not None: # login_in 两参数:request, user # 实际是对request写了一部分东西进去,而后在render的时候: # request是要render回去的。这些信息也就随着返回浏览器。完成登陆 login(request, user) # 跳转到首页 user request会被带回到首页 return render(request, "index.html") # 验证不成功跳回登陆页面 # 没有成功说明里面的值是None,并再次跳转回主页面 else: return render(request, "login.html", {"msg": "用户名或密码错误! "})
好比:既然表单都验证失败了,就不用显示密码出错了数据库
# 仅当用户真的密码出错时 else: return render(request, "login.html",{"msg":"用户名或密码错误!"}) # 验证不成功跳回登陆页面 # 没有成功说明里面的值是None,并再次跳转回主页面 else: return render( request, "login.html", { "login_form": login_form })
forms中的名称username和password必须和html中的一致。毕竟他是使用的request.POST
而request是从前面传过来的。django
实例化LoginView
时已经对于咱们的字段进行了验证。
打上断点:
debug
后f6
运行到
此时能够看到errors(ErrorDict)
中的错误
将form传回前端:
前端中取值:
给这个class加上errorput会显示红色外框。
注意:写在class里面
<div class="error btns login-form-tips" id="jsLoginTips"> {% for key, error in login_form.errors.items %} {{ error }} {% endfor %} {{ msg }}</div>
本小节完毕对应commit:
6-4 & 5 登陆换用类继承view实现,使用Django form进行表单验证并把错误信息提示到前台。
咱们本节来说session和cookie
User1如何实现登陆的。
cookie是浏览器支持的一种本地存储方式。以dict,键值对方式存储。
{"sessionkey": "123"}
浏览器会自动对于它进行解析。
用户向服务器发起的两次请求之间是没有状态的。也就是服务器并不知道这是同一个用户发的。
作到记住用户:
浏览器a在向服务器发起请求,服务器会自动给浏览器a回复一个id,浏览器a把id放到cookie当中,在下一次请求时带上这个cookie里的id值向浏览器请求,服务器就知道你是哪一个浏览器发过来的了。
服务器a
发回来的id
会放到服务器a
的域之下。不能跨域访问cookie。
使用浏览器随便打开一个网页,而后f12
打开。
好比我使用的Chrome
浏览器
会找到存储在浏览器本地的cookie值
点击clear all
清空全部的cookie
f5
刷新页面,会发现又把这些cookie值进来。
若是将用户名和密码直接保存在cookie,能够实现最垃圾最简略版本的自动登陆。
用户在第一次请求后,浏览器回复的id既能够是用户的user id。
也能够一段任意的字符串,咱们把它叫作session id
根据用户名和密码,服务器会采用本身的规则生成session id
。这个session id
保存在本地cookie。浏览器请求服务器会携带。
session id
取出这些基本信息。Django的默认表中的session
表就记录了用户登陆时,后端咱们Django为用户生成的sessionid
。
能够看到session key value
和过时时间。
咱们能够清空这张表的数据。运行项目进行登陆。
能够看到咱们刚刚生成的session id。
此时经过f12
查看浏览器在本地存储的session id
。能够看到以下图和咱们数据库中的一致。
session_key 发到浏览器叫作session id
经过session id 用户访问任何一个页面都会携带,服务器就会认识。
Setting.py中,
这个app会拦截咱们每次的request请求,在request
中找到session id,而后去数据表中进行查询。
而后经过session key
去找到session data
。此时直接为咱们取出了user。
在服务器返回浏览器的response
中也会直接加上session id
cookie是浏览器本地存储机制,存在域名之下,存储不安全。
服务器在返回id时经过规则生成一串字符,并设置了过时时间。存储在服务器端(数据库)
users/views.py
# 注册功能的view class RegisterView(View): # get方法直接返回页面 def get(self, request): return render(request, "register.html", {})
Django1.9.8 url配置以下:
from users.views import RegisterView # 注册url url("^register/", RegisterView.as_view(), name="register"),
Django2.0.1 url配置以下
from users.views import RegisterView # 注册url path("register/", RegisterView.as_view(), name = "register" )
此时访问首页发现能够成功跳转到注册页面
他会自动根据setting中配置,为咱们加上前缀
若是咱们把目录在setting中改到mystatic。url中会自动添加指定的前缀
能够看到能够访问成功。
枯燥可是要有耐心。
这时候访问三个页面,查看样式是否无缺。
https://github.com/mbi/django-simple-captcha
workon mxonline3 pip install django-simple-captcha workon mxonline2 pip install django-simple-captcha==0.4.6
Add captcha
to the INSTALLED_APPS
in your settings.py
Add an entry to your urls.py
:
django1.9.8以下:
from django.conf.urls import url, include urlpatterns += [ url(r'^captcha/', include('captcha.urls')), ]
django2.0.1以下;
# 验证码url path("captcha/", include('captcha.urls'))
makemigrations migrate
进入数据库查看生成的表
users/forms.py:
# 引入验证码field from captcha.fields import CaptchaField # 验证码form & 注册表单form class RegisterForm(forms.Form): # 此处email与前端name需保持一致。 email = forms.EmailField(required=True) # 密码不能小于5位 password = forms.CharField(required=True, min_length=5) # 应用验证码 captcha = CaptchaField()
users/views.py
# form表单验证 & 验证码 from .forms import LoginForm, RegisterForm # 注册功能的view class RegisterView(View): # get方法直接返回页面 def get(self, request): # 添加验证码 register_form = RegisterForm() return render(request, "register.html", {'register_form':register_form})
找到上图验证码部分。修改成下图
Forms中的field会生成不一样的框。
咱们只有label可是前端能够查看到input框等,也就是Registerform会为咱们生成输入框+验证码。
隐藏的字符串的框会被带到后台,由Django为咱们进行验证。验证该验证码是否保存过。
能够看得咱们数据库中将这个hashkey进行了保存。这个key与验证码内容对应。
后台会把验证码值 和 hashkey进行联合查询。
users/views.py的RegisterView中添加post方法:
def post(self, request): # 实例化form register_form = RegisterForm(request.POST) if register_form.is_valid(): pass
修改form表单提交方式与提交到哪一个url
前端的form提交加上对应的crsf token
刷新验证码是前端帮咱们完成的:
//刷新验证码 function refresh_captcha(event){ $.get("/captcha/refresh/?"+Math.random(), function(result){ $('#'+event.data.form_id+' .captcha').attr("src",result.image_url); $('#id_captcha_0').attr("value",result.key); }); return false; }
from django.contrib.auth.hashers import make_password if register_form.is_valid(): user_name = request.POST.get("email", "") pass_word = request.POST.get("password", "") # 实例化一个user_profile对象,将前台值存入 user_profile = UserProfile() user_profile.username = user_name user_profile.email = user_name # 加密password进行保存 user_profile.password = make_password(pass_word) user_profile.save() pass
setting中配置;
# 发送邮件的setting设置 EMAIL_HOST = "smtp.qq.com" EMAIL_PORT = 25 EMAIL_HOST_USER = "mxonline.mtianyan.cn" EMAIL_HOST_PASSWORD = " " EMAIL_USE_TLS= True EMAIL_FROM = "mxonline.mtianyan.cn"
新建package后新建文件。
apps:utils/email_send.py
:
# encoding: utf-8 from random import Random __author__ = 'mtianyan' __date__ = '2018/1/10 0010 20:47' from users.models import EmailVerifyRecord # 导入Django自带的邮件模块 from django.core.mail import send_mail # 导入setting中发送邮件的配置 from Mxonline2.settings import EMAIL_FROM # 生成随机字符串 def random_str(random_length=8): str = '' # 生成字符串的可选字符串 chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789' length = len(chars) - 1 random = Random() for i in range(random_length): str += chars[random.randint(0, length)] return str # 发送注册邮件 def send_register_eamil(email, send_type="register"): # 发送以前先保存到数据库,到时候查询连接是否存在 # 实例化一个EmailVerifyRecord对象 email_record = EmailVerifyRecord() # 生成随机的code放入连接 code = random_str(16) email_record.code = code email_record.email = email email_record.send_type = send_type email_record.save() # 定义邮件内容: email_title = "" email_body = "" if send_type == "register": email_title = "mtianyan慕课小站 注册激活连接" email_body = "请点击下面的连接激活你的帐号: http://127.0.0.1:8000/active/{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 若是发送成功 if send_status: pass
上图为qq邮箱开启smtp服务
点击生成受权码
def post中加上发送邮件
users/views.py
:
# 发送邮件 from utils.email_send import send_register_eamil # 发送注册激活邮件 send_register_eamil(user_name, "register")
点击注册提交,由于咱们没有return。一直在转圈圈。
可是数据库中已经添加了字段。
能够看到咱们的邮件已经被发送到邮箱中。
若是注册成功返回login页面:不成功,返回register页面并报错。
找猫画虎:将login中的错误提示搬运到register中来。
若是传回的有值则,显示传回来值。
密码也作一样操做
post方法中
# 默认激活状态为false user_profile.is_active = False
书写处理激活的view。
# 激活用户的view class ActiveUserView(View): def get(self, request, active_code): # 查询邮箱验证记录是否存在 all_record = EmailVerifyRecord.objects.filter(code = active_code) # 激活form负责给激活跳转进来的人加验证码 active_form = ActiveForm(request.GET) # 若是不为空也就是有用户 if all_record: for record in all_record: # 获取到对应的邮箱 email = record.email # 查找到邮箱对应的user user = UserProfile.objects.get(email=email) user.is_active = True user.save() # 激活成功跳转到登陆页面 return render(request, "login.html", ) # 本身瞎输的验证码 else: return render(request, "register.html", {"msg": "您的激活连接无效","active_form": active_form})
配置用户激活的url并经过url提取到变量:
django1.9.8:
# 激活用户url url(r'^active/(?P<active_code>.*)/$',ActiveUserView.as_view(), name= "user_active")
django2.0.1:
# 激活用户url re_path('active/(?P<active_code>.*)/', ActiveUserView.as_view(), name= "user_active")
这里经过?p
将后面.*
表明所有提取的正则,符合的内容传入参数active_code中/$
表明以/$
为结尾
其余细节根据本身须要进行优化。
注册功能制做完毕。对应commit:
注册功能实现完毕,流程:注册,发邮件,激活,登陆。对应6-6,7,8,9,10
原文学习来自简书,做者:天涯明月笙连接:https://www.jianshu.com/p/9c621518d991