Django学习纪录 13.用户的登入与登出

之前有在用Django写一些小网站,现在暑假想说再来複习一下之前买的这本书
http://img2.58codes.com/2024/20118889bj9fH1vhuR.jpg
于是我就把它写成一系列的文章,也方便查语法
而且因为这本书大概是2014年出的,如今Django也已经出到2.多版
有些内容也变得不再支援或适用,而且语法或许也改变了
所以我会以最新版的Python和Django来修正这本书的内容跟程式码

目录:django系列文章-Django学习纪录

13. 用户的登入与登出

13.1 用户

使用django内建的用户权限系统
settings.py

INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth', # <-确认此行有加    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'restaurants',]MIDDLEWARE = [    'django.middleware.security.SecurityMiddleware',    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.locale.LocaleMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware', # <-确认此行有加    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',]

如果是第一次安装记得同步资料库

python manage.py migrate

13.2 登入

13.2.1 确认使用者身分

首先设定一个登入页面
mysite/templates/login.html

<!DOCTYPE html><html lang="en">    <head>        <meta charset="UTF-8">        <title>登入</title>    </head>    <body>        <form action="" method="post">            <label for="username">用户名称:</label>            <input type="text" name="username" value="" id="username"> <br/>            <label for="password">用户密码:</label>            <input type="password" name="password" value="" id="password"> <br/>            <input type="submit" value="登入" />        </form>    </body></html>

views.py

...from django.contrib import authdef login(request):    if request.user.is_authenticated:        return HttpResponseRedirect('/index/')    username = request.POST.get('username', '')    password = request.POST.get('password', '')    user = auth.authenticate(username=username, password=password)    if user is not None and user.is_active:        auth.login(request, user)        return HttpResponseRedirect('/index/')    else:        return render(request, 'login.html', locals())...

HttpRequest物件中包含了一个user属性,代表了当前的使用者
如果用户已经登入,则HttpRequest.user是一个User物件,也就是具名用户
如果使用者尚未登入,HttpRequest.user是一个AnonymousUser物件,也就是匿名用户
User物件中的常用属性:

属性说明username使用者的帐号,由字母、数字和底线组成is_anonymous是否是匿名用户,永远回传False,若为AnonymousUser物件,则永远回传Trueis_authenticated用户是否认证过,永远回传True,若为AnonymousUser物件,则永远回传Falsefirst_name名字last_name姓氏email电子邮箱password加密(经编码)过后的密码is_staff真假值,若为True,该用户可登入admin后端is_active真假值,若为True,该用户可登入is_superuser真假值,若为True,该用户拥有全权限last_login用户上一次登入的日期与时间date_joined用户被创建的日期与时间User物件中的常用方法:属性说明--------------------------get_username()取得用户帐号get_full_name()回传完整的姓名get_short_name()只回传名字set_password(password)设定密码,会自动编码加密,不包含User物件的储存check_password(password)确认密码,正确会回传True,会自动编码加密才比较如果使用者已经认证过,我们将它重导回首页(等等我们会设计index.html)如果还是匿名用户,我们试图从request.POST中拿取表单中的帐密资讯(如果POST中没有username或是password的话,我们填给他一个空值,让他在接下来的检查中产生失败),并且使用auth中的authenticate方法来确认用户而auth.authenticate方法接受两个引数username、password如果帐密正确会回传具名用户的User物件如果不正确则回传None而user.is_active确认该帐户有没有被冻结只要任何检查有问题就回到登入页面让使用者输入帐密如果检查都通过就使用auth.login方法来登入

13.2.2 登入使用者并保持其登入

auth.login需要一个HttpRequest物件和一个User物件当做引数,他会利用Django的session将这个具名用户保存在该session中,这也代表了该用户的登入状态得以跨页面的保存直到session结束或登出
Django中所谓的已经登入,代表在当下的HttpRequest中的user属性是一个具名的User物件

13.2.3 根据用户身分,确认并规範使用者的操作功能

製作首页
mysite/templates/index.html

<!DOCTYPE html><html lang="en">    <head>        <meta charset="UTF-8">        <title>Restaurant King</title>    </head>    <body>        <h2>欢迎来到餐厅王</h2>        {% if request.user.is_authenticated %}            <p>{{request.user}} 您已经登入啰</p>            <a href="/restaurants_list/">餐厅列表</a>        {% else %}            <p>您尚未登入喔~<a href="/accounts/login/">登入</a></p>        {% endif %}    </body></html>

views.py

...def index(request):    return render(request, 'index.html')...

urls.py

from restaurants.views import login, indexurlpatterns = [    ...    path('index/', index),    path('accounts/login/', login),    ...]

至于为何要使用/accounts/login/这个pattern
因为/accounts/login/是Django默认的登入pattern(对于登出而言,/accounts/logout/也是默认值),这个pattern对于某些Django的函式而言是参数的预设值,使用默认的pattern可以使得我们在使用到这些函式时减少一些负担,不过如果没有其他考量的话,使用任何想要的pattern都是可以的
我们也可以在settings.py来设定此一默认值,LOGIN_URL可以修改成任意想要的默认pattern
http://img2.58codes.com/2024/201188898sxVCTFcJb.png
http://img2.58codes.com/2024/20118889kTHUBBPlpC.png

13.3 登出

views.py

...def logout(request):    auth.logout(request)    return HttpResponseRedirect('/index/')...

这里的auth.logout方法会将用户登出
只是要注意的是这个方法用在匿名用户上也不会产生错误
index.html

<!DOCTYPE html><html lang="en">    <head>        <meta charset="UTF-8">        <title>Restaurant King</title>    </head>    <body>        <h2>欢迎来到餐厅王</h2>        {% if request.user.is_authenticated %}            <p>                {{request.user}} 您已经登入啰~                <a href="/accounts/logout/">登出</a>            </p>            <a href="/restaurants_list/">餐厅列表</a>        {% else %}            <p>您尚未登入喔~<a href="/accounts/login/">登入</a></p>        {% endif %}    </body></html>

urls.py

from restaurants.views import login, index, logouturlpatterns = [    ...    path('index/', index),    path('accounts/login/', login),    path('accounts/logout/', logout),    ...]

http://img2.58codes.com/2024/20118889RzQz8FsUyS.png
http://img2.58codes.com/2024/20118889aS9wfakLRz.png

13.4 使用内建的login/logout视图

Django其实已经撰写好了登出与登入的视图函式
使用方法:
urls.py

...from django.contrib.auth import viewsurlpatterns = [    ...    path('index/', index),    path('accounts/login/', views.LoginView.as_view()),    path('accounts/logout/', views.LogoutView.as_view()),    path('accounts/profile/', index),    ...]

这两个视图函式预设使用的模板分别是在
registration/login.html和registration/logged_out.html
所以把mysite/templates/login.html複製到registration资料夹中
把mysite/templates/index.html複製到registration资料夹并重新命名为logged_out.html
就可以正常使用了

13.4.2 内建login提供给呼叫模板的变量

提供给模板的主要有下列变量

变量说明formAuthenticationForm的物件,用来做authenticate的确认的,有username和password两个栏位next用在登入成功后重导的URL,可能包含查询字串mysite/templates/registration/login.html
...    <body>        <form action="{% url 'login' %}" method="post">        {% csrf_token %}        <table>            {{ form.as_table }}        </table>        <input type="submit" value="登入" />        </form>    </body>...

在url pattern中加入name这个参数

path('accounts/login/', views.LoginView.as_view(), name='login'),path('accounts/logout/', views.LogoutView.as_view(), name='logout'),

http://img2.58codes.com/2024/20118889O1XRY8IpEF.png
介绍一下{% url '字串' %}的用法
django会将这里的字串对应到符合的name参数的url pattern
例如{% url 'login' %}即为对应到path('accounts/login/', views.LoginView.as_view())
这是一个极佳的"反查"手段避免我们将URL写死在模板里

13.4.3 提供重导URL给内建login

使用者登入之后,我们经常要帮他重导回某个特定的页面,譬如首页
内建的login预设会重导回/accounts/profile/
这就是为什么我们要加入

path('accounts/profile/', index)

如果删去这行
但是仍要让内建的login能够照我们的意思来重导
有以下几种方法:

于settings.py中设定LOGIN_REDIRECT_URL

LOGIN_REDIRECT_URL = "/index/"

透过POST方法传送next(或是其他的REDIRECT_FIELD_NAME)栏位及其值

mysite/templates/registration/login.html

...        <input type="submit" value="login" />        <input type="hidden" name="next" value="{{ next }}" /> <!--利用此行-->    </form>...

利用名为next的隐藏元件来传送重导URL,而这个URL是来自内建login提供的变量{{ next }}

透过GET方法传送next(或是其他的REDIRECT_FIELD_NAME)栏位及其值

直接透过在登入URL: /accounts/login/?next=/index/中附加查询字串来提供next栏位
mysite/templates/registration/login.html

...<body>        <form action="{% url 'login' %}?next=/index/" method="post">        {% csrf_token %}        <table>            {{ form.as_table }}        </table>        <input type="submit" value="登入" />        </form>    </body>...

不过第二种方法还是依据第一种方式的设定,只能算是解决next值传递的方式而不算是设定一个next栏位的方法
对于预设的重导行为会偏向使用第一种方式进行设定,对于重导回登入前一个页面的行为会偏向使用第三个方法
如果没有特殊需求的话,建议各位遵循使用next这个栏位名称,可以在使用上避免一些需要调整的负担,也能有较好的一致性

13.4.4 对于内建的login视图使用别的模板名称

path('accounts/login/', views.LoginView.as_view(template_name='login.html'), name='login'),path('accounts/logout/', views.LogoutView.as_view(template_name='index.html'), name='logout'),

加入template_name这个参数便可以使用模板目录底下任意的模板了

上一篇:Django学习纪录 12.Cookies与Sessions

下一篇:Django学习纪录 14.权限与注册


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章