Django搭建个人博客:用户的登录和登出

5344阅读 · 19评论 · 2018/11/02发布   前往评论

用户管理

用户数据可以说是大部分网站最重要的资产。用户管理就是对用户数据进行增删改查等操作的功能,自然也就非常的重要了。

本章开始学习用户管理的内容,首先从用户登录开始。

在Django中用app来区别不同功能的模块,达到代码隔离和复用。因为用户管理和博客文章的功能不同,因此需要新建一个专门的app。

进入虚拟环境,运行startapp指令创建新的app:

python manage.py startapp userprofile

查看项目目录,发现已经新生成了userprofile目录及其中的文件了。

再遇表单类

用户登录时,需要填写账户密码等表单数据,因此又要用到Form表单类。

userprofile目录中创建表单类的文件forms.py,编写如下代码:

/userprofile/forms.py

# 引入表单类
from django import forms
# 引入 User 模型
from django.contrib.auth.models import User

# 登录表单,继承了 forms.Form 类
class UserLoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField()

在前面发表文章的模块中,表单类继承了forms.ModelForm,这个父类适合于需要直接与数据库交互的功能,比如新建、更新数据库的字段等。如果表单将用于直接添加或编辑Django模型,则可以使用 ModelForm来避免重复书写字段描述。

forms.Form则需要手动配置每个字段,它适用于不与数据库进行直接交互的功能。用户登录不需要对数据库进行任何改动,因此直接继承forms.Form就可以了。

编写视图

用户的登录是比较复杂的功能,好在Django提供了封装好的模块供我们使用。

首先在userprofile/views.py中写视图函数:

/userprofile/views.py

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from .forms import UserLoginForm

# Create your views here.

def user_login(request):
    if request.method == 'POST':
        user_login_form = UserLoginForm(data=request.POST)
        if user_login_form.is_valid():
            # .cleaned_data 清洗出合法数据
            data = user_login_form.cleaned_data
            # 检验账号、密码是否正确匹配数据库中的某个用户
            # 如果均匹配则返回这个 user 对象
            user = authenticate(username=data['username'], password=data['password'])
            if user:
                # 将用户数据保存在 session 中,即实现了登录动作
                login(request, user)
                return redirect("article:article_list")
            else:
                return HttpResponse("账号或密码输入有误。请重新输入~")
        else:
            return HttpResponse("账号或密码输入不合法")
    elif request.method == 'GET':
        user_login_form = UserLoginForm()
        context = { 'form': user_login_form }
        return render(request, 'userprofile/login.html', context)
    else:
        return HttpResponse("请使用GET或POST请求数据")
  • 跟发表文章的表单类类似,Form对象的主要任务就是验证数据。调用is_valid()方法验证并返回指定数据是否有效的布尔值。

  • Form不仅负责验证数据,还可以“清洗”它:将其标准化为一致的格式,这个特性使得它允许以各种方式输入特定字段的数据,并且始终产生一致的输出。一旦Form使用数据创建了一个实例并对其进行了验证,就可以通过cleaned_data属性访问清洗之后的数据。

  • authenticate()方法验证用户名称和密码是否匹配,如果是,则将这个用户数据返回。

  • login()方法实现用户登录,将用户数据保存在session中。

其他的内容就跟发表文章时的技巧类似了。

什么是session

Session在网络应用中,称为“会话控制”,它存储特定用户会话所需的属性及配置信息。

当用户在 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。

Session 最常见的用法就是存储用户的登录数据。

详情看这里:Session百度百科

登录的模板

接着写模板文件。

创建/templates/userprofile/login.html模板:

/templates/userprofile/login.html

{% extends "base.html" %} {% load staticfiles %}
{% block title %} 登录 {% endblock title %}
{% block content %}
<div class="container">
    <div class="row">
        <div class="col-12">
            <br>
            <form method="post" action=".">
                {% csrf_token %}
                <!-- 账号 -->
                <div class="form-group">
                    <label for="username">账号</label>
                    <input type="text" class="form-control" id="username" name="username">
                </div>
                <!-- 密码 -->
                <div class="form-group">
                    <label for="password">密码</label>
                    <input type="password" class="form-control" id="password" name="password">
                </div>
                <!-- 提交按钮 -->
                <button type="submit" class="btn btn-primary">提交</button>
            </form>
        </div>
    </div>
</div>
{% endblock content %}

内容与使用Form表单类发表新文章非常类似。唯一新知识是输入密码表单的type="password",可以让输入密码的时候显示小圆点,避免有人偷窥。

然后我们改写一下tempalates/header.html,把登录的按钮加进去:

/tempalates/header.html

...
<ul class="navbar-nav">
    ...

    <li class="nav-item">
        <a class="nav-link" href="{% url 'article:article_list' %}">文章</a>
    </li>

    <!-- Django的 if 模板语句 -->
    {% if user.is_authenticated %}
        <!-- 如果用户已经登录,则显示用户名下拉框 -->
        <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
              {{ user.username }}
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="dropdown-item" href="#">退出登录</a>
            </div>
        </li>
    <!-- 如果用户未登录,则显示 “登录” -->
    {% else %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'userprofile:login' %}">登录</a>
        </li>                    
    <!-- if 语句在这里结束 -->
    {% endif %}
</ul>
...

这里使用了新的模板语法:{% if ... %},用来判断用户是否已经登录:

  • 如果用户已经登录,则显示一个名字为用户名称的下拉框,就像通常的社交网站一样。
  • 如果用户未登录,则显示“登录”两个字提醒用户可以点击登录。

is_authenticatedmodels.User类的属性,用于判断用户是否已通过身份验证。

url及其他设置

最后的步骤就是将app配置到项目中去。

创建userprofile/urls.py文件:

/userprofile/urls.py

from django.urls import path
from . import views

app_name = 'userprofile'

urlpatterns = [
    # 用户登录
    path('login/', views.user_login, name='login'),
]

配置根路由my_blog/urls.py

/my_blog/urls.py

...

urlpatterns = [
    ... 
    # 用户管理
    path('userprofile/', include('userprofile.urls', namespace='userprofile')),
]

配置my_blog/settings.py

my_blog/settings.py

...
INSTALLED_APPS = [
    ...
    'userprofile',
]
...

因为userprofile这个app并没有改动model,因此不用迁移数据。

OK了,运行服务器,在admin后台中退出登录(找找页面右上角),返回到文章列表页:

点击登录按钮,输入账号和密码(可以故意输错试试会出现什么):

点击提交,将自动回到文章列表页面:

大功告成。

用户的退出

有了用户登录的知识后,用户退出就很简单了。这里就直接给出代码,相信你一定能看懂。

还是先添加用户退出的视图:

/userprofile/views.py

...
# 引入logout模块
from django.contrib.auth import authenticate, login, logout

...
# 用户退出
def user_logout(request):
    logout(request)
    return redirect("article:article_list")

然后配置/userprofile/urls.py

/userprofile/urls.py

...

urlpatterns = [
    path('login/', views.user_login, name='login'),

    # 用户退出
    path('logout/', views.user_logout, name='logout'),
]

在写登录的代码时,已经给用户退出留好了接口,因此只需要改动/templates/header.html

/templates/header.html

...
# 改动 href 中的链接指向
<a class="dropdown-item" href='{% url "userprofile:logout" %}'>退出登录</a>

...

保存后刷新页面,点击下拉框中“退出登录”选项,用户就顺利退出了。

总结

本章用到了表单类、if模板语句、用户验证等知识完成了用户管理的登录和退出。

接下来学习如何实现注册和删除。

转载请告知作者并注明出处。




本文作者: 杜赛
发布时间: 2018年11月02日 - 21:27
最后更新: 2019年03月10日 - 21:13
知识共享许可协议   转载请保留原文链接及作者


登录 后回复

共有19条评论

avatar
Python 么么哒! 3

你好!

user = authenticate(username=data['username'], password=data['password2'])

password2 应该改为 password.不然报错,且无法登陆。

8个月前 回复


avatar
杜赛 [博主] Python 么么哒! 3

对的,这个地方有笔误,应该改为password。已经更正过来了。

感谢指正!wink

8个月前 回复


avatar
pidada 么么哒! 3

博主   登录界面做好了  也可以正常运行 

但是为什么“写文章”的按钮消失了,你是不是在这个章节中还有其他代码的变动

5个月前 回复


avatar
杜赛 [博主] pidada 么么哒! 3

有点忘了。“写文章”按钮后来应该是挪到下拉框里去了。因为普通用户不需要这个入口。

5个月前 回复


avatar
pidada 么么哒! 3

博主 你的截图中“写文章  文章   登录”,这个是在没有登录的情况下吧?

我的这个界面中没有“写文章”,不知道是什么情况

5个月前 回复


avatar
杜赛 [博主] pidada 么么哒! 3

写文章这个入口在前面的章节中就讲过了

5个月前 回复


avatar
ac1864 么么哒! 3

 过关了。

谢谢大佬准备的优秀的入门教程。

4个月前 回复


avatar
杜赛 [博主] ac1864 么么哒! 3

不客气,继续往下撸

4个月前 回复


avatar
Nl-Lin 么么哒! 3

有个问题

 <form method="post" action=".">
                {% csrf_token %}
                <!-- 账号 -->

action 我改成 {% url 'article:article_list' %},跳转到这个页面,右上角的只显示登陆!!! 

也就是说

{% if user.is_authenticated %}

执行了else...

可以说一下吗???

4个月前 回复


avatar
杜赛 [博主] Nl-Lin 么么哒! 3

不是很清楚你这个问题在哪。再具体描述一下相关信息呢

4个月前 回复


avatar
haha 么么哒! 3

请问博主,我在注册微博第三方登陆的时候,提示你的应用“xxx网站”申请驳回 驳回理由:微博登陆按钮无法正常使用,请修复后再提交审核,微博登入功能接入地址:https://open.weibo.com/wiki/Connect/login, 请问微博注册的流程是啥啊,还有那个取消回调地址怎么填呢?

4个月前 回复


avatar
杜赛 [博主] haha 么么哒! 3

这些都是微博定的规矩,我真记不太清楚了。

我自己也是跟着一些博客文章弄的,您试着搜索一下,应该有很多可参考的文章。

大概就是需要在新浪开放平台注册,按着微博给的文档往下走。

取消授权回调我是没有填的,可以正常工作。

4个月前 回复


avatar
haha 杜赛 [博主] 么么哒! 3

4个月前 回复


avatar
sys0613 么么哒! 4

在header.html中有如下这句,请问这个user是默认在模板中就可以使用的对象么?好像view中没有传递它过来呢?都有哪些是在html中可以直接使用的对象呢,我打印request中出现的对象是不是就代表可以在html模板中直接使用?谢谢博主

{% if user.is_authenticated %}

-------------------------------------------------------------------------------------------------------------------------------------------在网上找到答案了,一个是user,一个是perms。是默认就有的。

引用的原文地址:https://www.cnblogs.com/wangwei916797941/p/7398969.html 内容如下:

在界面中使用许可

接下来,我们需要探讨一下如何在Template(模板)中使用许可。因为有的时候需要在界面上,通过一些许可来控制界面的显示。

在Django中在界面上进行权限设置非常方便,因为Django为你做了很多工作。

在模版代码中,有两个属性,是Django给你提供好的,一个是user,一个是perms。

比方说我们可以这样判断一个用户是否是登陆用户,进而作出不同的显示:

{% if user.is_authenticated %}

    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>

{% else %}

    <p>Welcome, new user. Please log in.</p>

{% endif %}

user变量是一个User或者AnoymousUser对象。

perms变量是一个django.contrib.auth.context_processors.PermWrapper对象,对当前用户的User.has_module_perms和User.has_perm进行了封装。这个包装器让你使用perm起来非常的方便。比如,我们需要判断当前用户是否拥有school应用下的所有权限,则使用

{{perms.school}}

我们如果判断当前用户是否拥有school应用下发表讨论的权限,则使用{{perms.school.publish_discussion}}

3个月前 回复


avatar
杜赛 [博主] sys0613 么么哒! 3

是的,user是django提供给你可以直接用的。

你找的这篇已经讲得很清楚了,学习了~

3个月前 回复


avatar
1832218163 么么哒! 3

非常感谢博主热心的解答(本来都没期望会回复呢yes)由衷感谢!

2个月前 回复


avatar
杜赛 [博主] 1832218163 么么哒! 5

.is_valid()方法会将提交的表单数据与表单类里的定义做比对,如果不符合就返回False

比如说在表单类中定义的是邮箱字段,但是提交的数据却是数字,那么.is_valid()就会返回False

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid email address',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False

在调用了.is_valid()之后,你还可以用.errors来检查出错的位置:

>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}

注意.is_valid()方法用于已绑定数据的表单。对未绑定数据的表单是没有意义的:

>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}

官方文档相关部分讲得很详细,你可以稍微阅读一下。

2个月前 回复


avatar
Tewrence 么么哒! 3
本回复已被 Tewrence 删除

2个月前 回复


avatar
MFullStack 么么哒! 3

2个月前 回复