关于类视图(登录)(个人备忘录)
Django将成为我的个人备忘录。
这次我们将总结一下关于类视图(登录)的内容。
开发环境 fā
操作系统:mac
编辑器:vscode
Python版本:3.10.9
Django版本:4.1.0
若欲将未登录用户无法运行的视图进行多重继承,
或给需要登录的视图加上装饰器。
@method_decorator(login_required)
准备好(复习AbstractBaseUser等内容)
from django.db import models
from django.contrib.auth.models import (
BaseUserManager,AbstractBaseUser,PermissionsMixin
)
from django.urls import reverse_lazy
class UserManager(BaseUserManager):
def create_user(self,username,email,password=None):
if not email:
raise ValueError('メールアドレスをいれてください')
user =self.model(
username = username,
email = email
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,username,email,password=None):
user = self.model(
username=username,
email = email,
)
user.set_password(password)
user.is_staff=True
user.is_active=True
user.is_superuser=True
user.save(using=self._db)
return user
class Users(AbstractBaseUser,PermissionsMixin):
username = models.CharField(max_length=150)
email = models.EmailField(max_length=255,unique=True)
is_active=models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS=['username']
objects = UserManager()
def __str__(self):
return self.email+''+self.username
def get_absolute_url(self):
return reverse_lazy('accounts:home')
请不要忘记在settings.py中进行相应的设置。
AUTH_USER_MODEL = 'accounts.Users'
# Application definition
INSTALLED_APPS = [
#(略)
'accounts',
]
创建视图、创建注册表单、创建网址、创建可进行跳转的HTML。
from django.shortcuts import render
from django.views.generic.base import TemplateView,View
from django.views.generic.edit import CreateView,FormView
from .forms import RegistForm
class HomeView(TemplateView):
template_name = 'home.html'
class RegistUserView(CreateView):
template_name = 'regist.html'
form_class = RegistForm
class UserLoginView(FormView):
pass #のちに記述
class UserLogoutView(View):
pass #のちに記述
from django import forms
from django.contrib.auth import get_user_model
from .models import Users
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
User=get_user_model
class RegistForm(forms.ModelForm):
username=forms.CharField(label='名前')
age = forms.IntegerField(label='年齢',min_value=0)
email =forms.EmailField(label='メールアドレス')
password = forms.CharField(label='パスワード',widget=forms.PasswordInput)
confirm_password = forms.CharField(label='パスワード再入力',widget=forms.PasswordInput)
class Meta:
model=Users
fields = ('username','age','email','password')
def clean(self):
cleaned_data=super().clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password !=confirm_password:
raise ValidationError('パスワードが一致しません')
def save(self,commit=False):
user =super().save(commit=False)
validate_password(self.cleaned_data.get('password'),user)
user.set_password(self.cleaned_data.get('password'))
user.save()
return user
from django.urls import path
from .views import(
HomeView,RegistUserView,UserLoginView,UserLogoutView
)
app_name='accounts'
urlpatterns = [
path('home/',HomeView.as_view(),name='home'),
path('regist/',RegistUserView.as_view(),name='regist'),
path('user_login/',UserLoginView.as_view(),name='user_login'),
path('user_logout/',UserLogoutView.as_view(),name='user_logout'),
]
<!DOCTYPE html>
<html lang='ja'>
<head>
<meta charset='utf-8'>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<nav class ='navbar navbar-expand-lg navbar-light bg-light'>
<a class ='navbar-brand' href="{%url 'accounts:home'%}">ホーム</a>
{% if user.is_authenticated%} {#ログインしているかどうかで表示を切り替える#}
<a class ='navbar-brand' href="{%url 'accounts:user_logout'%}">ログアウト</a>
{% else %}
<a class ='navbar-brand' href="{%url 'accounts:user_login'%}">ログイン</a>
<a class ='navbar-brand' href="{%url 'accounts:regist'%}">ユーザ登録</a>
{% endif %}
</nav>
{% block content%}
{% endblock %}
</body>
</html>
实现登录与登出
关于登录,我们可以在forms.py中创建一个包含登录所需信息的表单,然后继承FormView,并在form_class中指定要使用的表单。
在post方法中,获取到POST请求中的email和password,并使用authenticate方法进行验证,如果成功验证,则使用login方法进行登录,并进行重定向。
在UserLogoutView中,使用get方法接收请求,并使用logout方法进行注销,并进行重定向。forms.py
class UserLoginForm(forms.Form):
email = forms.EmailField(label=’邮箱’)
password = forms.CharField(label=’密码’,widget=forms.PasswordInput)
views.py
class UserLoginView(FormView):
template_name = ‘user_login.html’
form_class = UserLoginForm
def post(self, request, *args, **kwargs):
email = request.POST[’email’]
password = request.POST[‘password’]
user = authenticate(email=email, password=password)
if user is not None and user.is_active:
login(request, user)
return redirect(‘accounts:home’)
class UserLogoutView(View):
def get(self, request, *args, **kwargs):
logout(request)
return redirect(‘accounts:user_login’)
设置不允许未登录用户执行的方法(LoginRequiredMixin,login_required)。
做法有三种:
1. 在dispatch方法中定义method_decorator(login_required)。
2. 在整个类中定义method_decorator(login_required, name=’dispatch’)。
3. 通过多重继承将LoginRequiredMixin添加到类中。
导入的东西
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin
# 2.@method_decorator(login_required,name='dispatch')
class UserView(LoginRequiredMixin,TemplateView): #3
template_name = 'user.html'
#1. @method_decorator(login_required) #ログインしていないと実行されない
#dispatchをオーバーライド
#dispatchとはgetリクエストならばgetをpostリクエストならpost処理を行うメゾット、だからリクエストの際必ず行われる
def dispatch(self,*args,**kwargs):
return super().dispatch(*args,**kwargs)

LOGIN_URL='/accounts/user_login' #デフォルトのaccounts/login/をにaccounts/user_loginにリダイレクト先を変更する
?next= 实现兼容(更智能的页面转移)
当login_required或LoginRequiredMixin不允许访问,并且在settings.py中通过LOGIN_URL进行了重定向到登录页面时,与正常访问登录页面不同,可以看到url参数中有?next=/accounts/user/。
?next=表示由于被阻止访问这个页面,如果能够登录成功,则会重定向到这个页面的信息。
如果存在next_url,则在登录时会跳转到要访问的页面,而不是跳转到主页等处理方式,
这需要做两步:
1.在登录的view中添加这个处理;
2.在登录的html中通过input标签的value属性POST了?next=后面的信息,这样处理会更加智能。
class UserLoginView(FormView):
template_name='user_login.html'
form_class=UserLoginForm
# success_url=reverse_lazy('accounts:home')
def post(self,request,*arg,**kwargs):
#POSTが行われたらemailとpasswordを取得して
email = request.POST['email']
password = request.POST['password']
#そのユーザが存在するかauthenticateで確かめる
user = authenticate(email=email,password=password)
#userが存在し、かつ、is_activeがTrueの場合にログインを行う
if user is not None and user.is_active:
login(request,user)
# ?nextがurlパラメータにあればそちらに移行する #追加
next_url =request.POST['next']
if next_url:
return redirect(next_url)
return redirect('accounts:home')
<input type="hidden" name="next" value="{{request.GET.next}}">
#request.GET.nextで?next=の後の情報をviewに投げることができる
登录视图,注销视图
from django.contrib.auth.views import LoginView #ログインするためのView
template_name= '' #表示するテンプレートの指定
authentication_form #ログイン認証に用いられるFormを指定(デフォルトはAuthenticationForm)
from django.contrib.auth.forms import AuthenticationForm #ログイン認証に用いられるForm(forms.pyで使うフォームに継承させる)
from django.contrib.auth.views import LogoutView #ログアウトするためのView
#settings.pyに設定する内容
LOGIN_REDIRECT_URL #LoginViewで次に遷移する先が指定されていなかった場合の遷移先のURL
LOGIN_URL #ログインしていない状態でlogin_requiredが指定されているViewを表示しようとした場合にリダイレクトされるView
LOGOUT_REDIRECT_URL #LogoutViewで次に遷移する先が指定されていなかった場合の遷移先のURL
我将继承LoginView,重新创建UserLoginView。
class UserLoginView(LoginView):
template_name='user_login.html'
authentication_form=UserLoginForm
class UserLogoutView(LogoutView):
pass
如果不指定登录后的跳转页面,将会出现页面找不到的错误。
LOGIN_REDIRECT_URL='/accounts/home'
LOGOUT_REDIRECT_URL='/accounts/user_login'
记住下次登录(更改会话保存时间)。
公式 –
SESSION_COOKIE_AGE #セッションの保存時間(秒) デフォルトは1209600(2週間)
公式:使用request.session.set_expiry(value)函数可以将会话的存储时间更改为传入的秒数。如果参数为0,则在关闭浏览器时会话将被删除。如果value是datetime或timedelta对象,则会话将在指定的日期时间被销毁。
SESSION_COOKIE_AGE=5 #5秒でセッションが解除される
在forms.py中添加一个用于保持登录状态的按钮。
class UserLoginForm(AuthenticationForm):
#ここでのusernameとはmodels.pyでのUSERNAME_FIELD = 'email'に設定したものを扱うのでEmailFieldをつかう
username= forms.EmailField(label='メールアドレス')
password= forms.CharField(label='パスワード',widget=forms.PasswordInput())
remember= forms.BooleanField(label='ログイン状態を保持する',required=False)
class UserLoginView(LoginView):
template_name='user_login.html'
authentication_form=UserLoginForm
#ログイン状態を保持する(session時間を変更する)
def form_valid(self,form):
#rememberを取り出してTrueであれば秒数を更新
remember=form.cleaned_data['remember']
if remember:
self.request.session.set_expiry(1200000)
return super().form_valid(form)