166.登录、退出登录以及登录限制案例
权限和分组
登录、注销和登录限制
1. 登录
在使用authenticate进行验证后,如果验证通过了,那么就会返回一个user对象,拿到user对象之后,可以使用django.contrib.auth.login进行登录,部分示例代码如下:
user = authenticate(username=username, password=password)
if user is not None and user.is_active:
login(request, user)
2. 注销:
注销、或者是退出登录,我们可以通过django.contrib.auth.logout来实现,它会调用flush()方法清除掉用户的session数据。部分示例代码如下:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
return HttpResponse('Success!')
3. 登录限制:
有时间,某个视图函数是需要经过登录才能访问的,那么我们就可以通过django.contrib.auth.decorators.login_required装饰器实现。示例代码如下:
from django.contrib.auth.decorators import login_required
<!--可以指定登录的url-->
@login_required(login_url='/login_logout/')
def profile(request):
return HttpResponse('个人中心!')
项目完整代码如下
(1)views.py文件中示例代码如下:
from django.http import HttpResponse
from djang.shortcuts import render, redirect, reverse
from .models import User
from .forms import login_logout_Form
from django.contrib.auth import authenticate, auth
from django.views import View
<!--1.首先定义一个添加用户信息的视图-->
def addview(request):
<!--1. 添加普通用户-->
user = User.objects.create_user(username='孤烟逐云', telephone='18833331111', password='111111')
user.email = 'ant@qq.com'
user.save()
return HttpResponse('successful!')
<!--2. 添加超级用户-->
user = User.objects.create_superuser(username='云中云', telephone='18833332222', password='111111')
user.email = 'ant01@qq.com'
user.save()
return HttpResponse('success!')
<!--表单的形式提交用户数据-->
<!--2. 之后定义一个首页类视图,如果是get请求,返回 一个模板;如果是post请求就采用表单验证提交的数据的合法性,如果合法就添加到数据库中-->
class login_logout(View):
def get(self, request):
return render(request, 'login_logout.html')
def post(self, request):
form = login_logout_Form(request.POST)
if form.is_valid():
telephone = form.clean_data.get('telephone')
password = form.clean_data.get('password')
remember = form.clean_data.get('remember')
user = authenticate(request, username=telephone, password=password)
<!--如果验证成功就会返回一个user对象,验证不成功,就返回None-->
if user and user.is_active:
login(request, user)
if remember:
<!--设置过期时间通过session.set_expiry(),设置为None的话,就会使用全局的-->
request.session.set_expiry(None)
else:
request.session.set_expiry(0)
return HttpResponse('登录成功!')
else:
return HttpResponse('用户名或密码不正确!')
<!--如果表单没有验证成功-->
else:
print(form.errors.get_json_data())
return redirect(reverse('login_logout:login_logout'))
(2)forms.py文件中示例代码如下:
from django import forms
from .models import User
from django.contrib.auth import get_user_model
class login_logout_Form(forms.ModelForm):
remember = forms.IntegerField(required=False)
class Meta:
model = get_user_model()
fields = ['telephone', 'password']
<!--如果你想要验证模型User中定义的所有字段, 就可以指定fields = '__all__'-->
(3)在urls.py文件中进行视图函数与url之间的映射。需要注意的是,一定要将类转换为类视图,即调用as_view()转换,示例代码如下:
from django.urls import path
from . import views
app_name = 'login_logout'
urlpatterns = [
path('', views.login_logout.as_view(), name='login_logout'),
path('add/', views.addview, name='add')
]
(1)否者的话,就会出现TypeError: init() takes 1 positional argument but 2 were given.
(2)并且需要注意的是,在调用Django内置的验证方法authenticate()验证的时候,第一个参数一定要传入request。
(4)这里使用的User模型,是我们通过继承AbstractBaseUser重写的User模型,对模型的字段进行了大幅度的改动,示例代码如下:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.contrib.auth import get_user_model
from django.contrib.auth import authenticate
class UserManager(BaseUserManager):
def _create_user_(self, telephone, username, password, **kwargs):
if not telephone:
raise ValueError('请输入密码!')
if not username:
raise ValueError('请输入用户名!')
# 注意,这里是self.model代表的是当前的User模型而不能写self.User()因为UserManager没有这个属性
user = self.model(telephone=telephone, username=username)
user.set_password(password)
user.save()
return user
def create_user(self, telephone, username, password, **kwargs):
kwargs['is_super'] = False
return self._create_user_(telephone=telephone, username=username, password=password, **kwargs)
def create_superuser(self, telephone, username, password, **kwargs):
kwargs['is_super'] = True
return self._create_user_(telephone=telephone, username=username, password=password, **kwargs)
# PermissionsMixin: 是定义用户时定义用户权限,必须继承
# AbstractBaseUser:User的基类其中涉及的字段最少,如果先定义自己的User模型,
# 将大部分Django中默认的字段删除的话,就可以继承该类
# AbstractBaseUser类中定义的字段有:password,last_login,is_active,is_super
class User(AbstractBaseUser, PermissionsMixin):
# 必须设置的两个字段username,email
username = models.CharField(max_length=100)
email = models.EmailField(unique=True)
telephone = models.CharField(max_length=11, unique=True)
is_active = models.BooleanField(default=True)
# 唯一性验证设置为telephone
USERNAME_FIELD = 'telephone'
# REQUIRED_FIELDS为空的列表代表的是,在验证用户登录的时候只需要输入password和USERNAME_FIELD指定的字段就行了
# 如果还想在验证用户的时候输入其他的字段,那么就可以将该字段设置在该列表中。
REQUIRED_FIELDS = []
# 以上自定义的User模型上并没有objects方法,所以我们需要自定义
objects = UserManager()
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
(5)如果使用这种继承AbstractBaseUser的方式进行重写Django内置的User模型的话,就需要告诉Django,现在要使用的是自己定义的User模型,这就需要在settings.py文件中配置:
AUTH_USER_MODEL = 'login_Logout.User'
(6)views.py文件中涉及的模板login_logout.html中的实例代码如下:
<form action="" method="post">
{% csrf_token %}
<table>
<tbody>
<tr>
<td>手机号:</td>
<td><input type="text" name="telephone"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td>
<label for="">
<input type="checkbox" name="remember" value="1">
</label>
</td>
<td></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</tbody>
</table>
</form>
需要注意的是,如果你在提交表单信息的时候没有加上{% csrf_token %}或者是,就会出现403的csrf禁止页面,所以可以选择一种方式进行添加。
之后就可以输入url进行登录验证了,这时会在pycharm终端打印出错误信息:{'telephone': [{'message': 'User with this Telephone already exists.', 'code': 'unique'}]}。因为在models.py文件中的模型User中定义的telephone字段就是唯一的,即unique=True,而且在forms文件中继承了User所有的字段,所以此时在验证的fields中指定telephone的话,就会验证数据库中的telephone的唯一性。
解决办法就是在forms.py文件的验证字段fields中不要指定telephone,可以重新定义一个字段telephone,示例代码如下:
class Login_logout_Form(forms.ModelForm):
remember = forms.IntegerField(required=False)
telephone = forms.CharField(max_length=11)
class Meta:
model = get_user_model()
fields = ['password']
此时,再次在浏览器中的表单中输入用户的信息telephone和password就可以登录成功了。
(7)定义个人中心的视图,示例代码如下:
def profile(request):
return HttpResponse('个人中心!')
在子urls.py文件中进行一层视图函数与url之间的映射,示例代码如下:
path('profile/', views.profile, name='profile'),
(8)此时,用户登录与否我们都可以通过url访问个人中心页面,这个有些不符合情理,我们可以将个人中心页面定义为只有用户登录之后,才能访问。
from django.contrib.auth.decorators import login_required
<!--login_required是一个定义好的装饰器-->
<!--装饰器中的login_url指定登录页面的url-->
@login_required(login_url='/login_logout/')
def profile(request):
return HttpResponse('个人中心!')
此时,我们如果在没有登录的情况下,去访问个人中心页面,就会跳转到登录页面url,http://127.0.0.1:8000/login_logout/?next=/login_logout/profile/, 登录之后就会重定向到个人中心页面。
(9)定义退出登录的视图logout_view,示例代码如下:
from django.contrib.auth import logout
def logout_view(request):
<!--logout()函数会将session中记录的sessionid清空,其实调用的就是flush()方法,sessionid的到期时间也会变为浏览器关闭就到期-->
logout(request)
return HttpResponse("退出登录!")
始于才华,忠于颜值;每件事情在成功之前,看起来都是天方夜谭。一无所有,就是无所不能。