当用户想切换登陆帐号,或者想退出登陆状态时,这时候就须要注销已登陆的帐号。如今咱们来为网站添加注销登陆的功能,这个功能 Django 也已经为咱们提供,咱们只需作一点简单配置。html
注销登陆
注销登陆的视图为 logout,咱们简单修改一下 index.html 的代码,添加一个注销登陆的按钮:数据库
templates/index.html
{% if user.is_authenticated %}
<p>你已登陆,欢迎你:<a href="#">{{ user.username }}</a></p> <button class="btn btn-default"><a href="{% url 'logout' %}">注销登陆</a></button> {% else %} <p>你尚未登陆,请 <button class="btn btn-default"><a href="{% url 'login' %}">登陆</a></button> 或者 <button class="btn btn-default"><a href="{% url 'users:register' %}">注册</a></button> </p> {% endif %}
若是你已经登录,就会看到一个注销登陆的按钮,点击该按钮就会跳转到注销登陆已成功地页面。再一次访问首页,你将看到登陆、注册按钮,说明你已经成功注销登陆状态了。浏览器
页面跳转
咱们以前在登陆、注册和注销的过程当中发现,登陆成功后会跳转到一个 404 页面,注册成功后返回的是首页,而注销登陆后跳转到了 Admin 后台的注销成功页面。对于一个网站来讲,比较好的用户体验是登陆、注册和注销后跳转回用户以前访问的页面。不然用户在你的网站东跳转西跳转好不容易找到了想看的内容,结果他已登陆给他跳转回了首页,这会使用户很是愤怒(我在有些网站就遇到过)。接下来咱们看看如何让登陆、注册和注销后跳转回用户以前访问的页面。安全
登陆和注销后返回当前页面
在登陆和注销的视图函数中,Django 已经为咱们处理了跳转回用户以前访问页面的流程。其实现的原理是,在登陆和注销的流程中,始终传递一个 next 参数记录用户以前访问页面的 URL。所以,咱们须要作的就是在用户访问登陆或者注销的页面时,在 URL 中传递一个 next 参数给视图函数,具体作法以下:数据结构
templates/index.html
<button class="btn btn-default"> <a href="{% url 'logout' %}?next={{ request.path }}">注销登陆</a> </button> <button class="btn btn-default"> <a href="{% url 'login' %}?next={{ request.path }}">登陆</a> </button>
能够看到,咱们在登陆和注销的 URL 后加了 next 参数,其值为 {{ request.path }}。request.path 是用户当前访问页面的 URL。在 URL 中传递参数的方法就是在要传递的参数前加一个 ?而后写上传递的参数名和参数值,用等号连接。关于在 URL 中传递参数具体请 HTTP 的相关协议。函数
为了在整个登陆流程中记录 next 的值,还须要在登陆表单中增长一个表单控件,用于传递 next 值。post
registration/login.html
<form class="form" action="{% url 'login' %}" method="post"> ... <button type="submit" class="btn btn-primary btn-block">登陆</button> <input type="hidden" name="next" value="{{ next }}"/> </form>
即在表单中增长了一个隐藏的 input 控件,其值为 {{ next }},即以前经过 URL 参数传递给登陆视图函数的,而后登陆视图函数又将该值传递给了 login.html 模板。这样在整个登陆流程中,始终有一个记录着用户在登陆前页面 URL 的变量 next 在视图和模板间来回传递,知道用户登陆成功后再跳转回 next 记录的页面 URL。网站
如今你能够点击登陆和注销的按钮来走一遍登陆和注销流程,发现页面跳转已经符合咱们的需求了。不过还由一点点小瑕疵,就是若是用户不是经过点击登陆和注销按钮,而是直接在页面输入 URL 来访问相关页面话,那这个 next 就没有值,从而没法向以前那样跳转回用户以前访问的页面。好比用户想登陆,他直接在浏览器的地址栏输入 /users/login/,因为在 URL 中没有传递 next,因此就没法记录用户登陆前的页面 URL,那在登陆成功后就没法将他带回登陆前的页面了。固然这种状况是极为罕见的,不多有用户会记住你网站的 URL 地址,但若是真有这样的用户,咱们就把他跳转回首页吧,由于没有任何办法记录他以前访问的页面。要想把用户跳转回首页,能够在 settings 中作以下设置:url
LOGOUT_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
这样,整个登陆和注销流程就造成了一个闭环。若是用户经过点击登陆或者注销按钮登陆和注销的话,在登陆或者注销成功后就会被带回登陆或者注销前的页面,不然将他带回网站首页。spa
注册后返回当前页面
相似的,咱们也但愿用户注册后返回注册前页面。不过因为注册视图函数是咱们本身写的,以前的处理方式是用户注册成功后将其带回网站首页,所以须要修改一下注册视图函数:
users/views.py def register(request): # 从 get 或者 post 请求中获取 next 参数值 # get 请求中,next 经过 url 传递,即 /?next=value # post 请求中,next 经过表单传递,即 <input type="hidden" name="next" value="{{ next }}"/> redirect_to = request.POST.get('next', request.GET.get('next', '')) # 只有当请求为 POST 时,才表示用户提交了注册信息 if request.method == 'POST': # request.POST 是一个类字典数据结构,记录了用户提交的注册信息 # 这里提交的就是用户名(username)、密码(password)、确认密码、邮箱(email) # 用这些数据实例化一个用户注册表单 form = RegisterForm(request.POST) # 验证数据的合法性 if form.is_valid(): # 若是提交数据合法,调用表单的 save 方法将用户数据保存到数据库 form.save() if redirect_to: return redirect(redirect_to) else: return redirect('/') else: # 请求不是 POST,代表用户正在访问注册页面,展现一个空的注册表单给用户 form = RegisterForm() # 渲染模板 # 若是用户正在访问注册页面,则渲染的是一个空的注册表单 # 若是用户经过表单提交注册信息,可是数据验证不合法,则渲染的是一个带有错误信息的表单 # 将记录用户注册前页面的 redirect_to 传给模板,以维持 next 参数在整个注册流程中的传递 return render(request, 'users/register.html', context={'form': form, 'next': redirect_to})
逻辑很是简答,就是首先尝试从用户的 GET 或者 POST 请求中获取 next 参数值,即在注册成功后须要跳转的 URL,若是有值,注册成功后跳转到该 URL,不然跳转回首页。同是不要忘记将该值传给模板,以维持 next 参数在整个注册流程中的传递。
接下来修改模板,和登陆模板的设置是同样的:
registration/login.html
<button class="btn btn-default"> <a href="{% url 'users:register' %}?next={{ request.path }}">注册</a> </button>
templates/users/register.html
<form class="form" action="{% url 'users:register' %}" method="post"> ... <button type="submit" class="btn btn-primary btn-block">注册</button> <input type="hidden" name="next" value="{{ next }}"/> </form>
注意:在注册视图函数中,对 next 的任意值咱们都进行了跳转,这可能致使一些安全问题。正确的作法应该是在跳转前,对须要跳转的 URL 作安全性检查。不过这里只做为一个示例,在实际项目中请仔细考虑可能的安全后果,以及添加必要的安全性检查代码。
OK,如此修改之后,用户的登陆、注册和注销流程的用户体验能够造成一个比较良好闭环了。接下来就来实现修改密码的功能。