注销和页面跳转

当用户想切换登录账号,或者想退出登录状态时,这时候就需要注销已登录的账号。现在我们来为网站添加注销登录的功能,这个功能 Django 也已经为我们提供,我们只需做一点简单配置。

注销登录

注销登录的视图为 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 值。

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 中做如下设置:

LOGOUT_REDIRECT_URL = '/'
LOGIN_REDIRECT_URL = '/'

这样,整个登录和注销流程就形成了一个闭环。如果用户通过点击登录或者注销按钮登录和注销的话,在登录或者注销成功后就会被带回登录或者注销前的页面,否则将他带回网站首页。

注册后返回当前页面

类似的,我们也希望用户注册后返回注册前页面。不过由于注册视图函数是我们自己写的,之前的处理方式是用户注册成功后将其带回网站首页,因此需要修改一下注册视图函数:

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,如此修改以后,用户的登录、注册和注销流程的用户体验可以形成一个比较良好闭环了。接下来就来实现修改密码的功能。

总结

本教程的示例项目代码位于 GitHub:Django Auth Example

如果遇到问题,请通过下面的方式寻求帮助。

更多 Django 相关教程,请访问我的个人博客:追梦人物的博客

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JetpropelledSnake

Python Web学习笔记之Cookie,Session,Token区别

2597
来自专栏Brian

Linux 基础知识

---- 简要 作为了一个服务端开发人员而言,不仅有强大的内功而且也需要对一些工具和运维方面的知识。Linux毋容置疑是每一个后端开发人员必须熟悉或者精通的“大...

4575
来自专栏我的小碗汤

vmware上安装linux过程记录

以前的电脑上安装过vmware+redhat,但是奈何电脑太老,配置太低,打开的时候超级卡,没法用。换了电脑后,再装上玩玩,故此记录一下安装过程。需要安装的小伙...

1201
来自专栏惨绿少年

日志切割之Logrotate

1753
来自专栏前端真相

你还在用U盘傻瓜式地拷贝文件吗?如何跨操作系统共享文件?

本文探讨macOS、Linux、Windows三种操作系统两两之间的文件共享方式,根据数学中的排列组合知识可知,总共有六种两两组合方式。

3204
来自专栏小樱的经验随笔

Linux目录结构

Linux 目录结构 装完Linux,首先需要弄清Linux 标准目录结构 ? / root —?启动Linux时使用的一些核心文件。如操作系统内核、引导程序G...

4276
来自专栏进击的君君的前端之路

项目脚手架搭建概要

1897
来自专栏区块链

Web安全常见漏洞修复建议

看各大发布漏洞的平台,发现众多挖洞大神精彩的漏洞发掘过程,但在修复建议或者修复方案处,给出千奇百怪神一般的回复,故而总结一下修复建议(才疏学浅不算太全敬请谅解,...

2956
来自专栏北京马哥教育

Gitlab CE 8.1.3 安装手册(Debian/Ubuntu)

安装概述 Gitlab的安装过程主要包括以下组件的配置: 安装软件包及解决依赖项 Ruby环境 Go 系统用户 数据库(Mysql/Postgresql) Re...

3355
来自专栏苦逼的码农

Linux达人养成计划2---虚拟机下的网络配置

当然也可以选择其他模式,不过这里,我们只讲桥接模式的,至于三种模式的区别,可以自行百度一下。

1313

扫码关注云+社区

领取腾讯云代金券