创建、注册、登录和注销Django自定义用户的功能(基于函数)

Table of Contents

用户模型创建
用户注册
用户登录
用户退出

创建用户模型

创建一个名为「accounts」的应用程序,并在「models.py」中定义Users模型。
导入两个模块:django.contrib.auth.models中的AbstractBaseUser和PermissionsMixin。
使Users模型继承AbstractBaseUser和PermissionsMixin。

AbstractBaseUser是一个只定义用户认证功能的类。

 

PermissionsMixin是一个定义了超级用户权限等的类。
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.contrib.auth.models import UserManager


class Users(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=255)
    email = models.EmailField(max_length=255, unique=True)
    icon = models.FileField(null=True, upload_to='icon/')
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email' #ユーザーを一意に識別する
    REQUIRED_FIELDS = ['username'] # スーパーユーザーに名前を持たせる

    class Meta:
        db_table = 'users' #テーブル名を指定

通过使用USERNAME_FIELD = ’email’,可以将电子邮件用作认证。

默认情况下,Django会使用自带的用户模型,所以要使用自定义用户模型,需要在「settings.py」中定义AUTH_USER_MODEL,并指定创建的Users模型。

AUTH_USER_MODEL = 'accounts.Users'

在进行迁移之前,请设置AUTH_USER_MODEL选项。一旦设置完成,就可以进行迁移了。

python manage.py makemigrations accounts

python manage.py migrate

用户注册

我会创建一个用于用户注册的表单。

在accounts文件夹中创建一个新的”forms.py”文件。
导入”models.py”中创建的Users和validate_password来进行密码验证。

from django import forms
from django.contrib.auth.password_validation import validate_password
from .models import Users


class SignInForm(forms.ModelForm):
    username = forms.CharField(label="名前")
    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', '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 forms.ValidationError('パスワードが一致しません。')
    
    def save(self):
        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

通过继承forms.ModelForm,可以使用save()方法将表单内容保存到数据库中。
通过将password和confirm_password指定为widget=forms.PasswordInput,可以创建用于输入密码的表单。另外,通过confirm_password要求用户再次输入密码,以预防密码输入错误的情况。

类元

在Meta类中用model=Users指定要注册表单内容的模型,并用fields指定要注册的字段(确认密码不会被注册到数据库中,因此被省略)。

清除方法

clean()方法会检查password和confirm_password是否匹配,如果不匹配,则返回验证错误。
cleaned_data = super()。clean()将输入的值从表单中取出,并存储在cleaned_data中。(super()指的是父类,在这种情况下指的是SignInForm)

# super().clean()により取得した値
{'username': 'test', 'email': 'test@example.com', 'password': 'noteapppass', 'confirm_password': 'noteapppass'}

将密码(password)和确认密码(confirm_password)作为cleaned_data.get(‘字段名’)的方式分别提取出来。

保存方法

为了避免默认的save方法导致密码以明文形式保存,我们需要重写save方法,将密码进行加密后再保存。
通过使用super().save(commit=False),我们可以获取表单的值(通过commit=False,可以仅获取值而不保存到数据库)。
使用validate_password对密码进行验证。
使用user.set_password方法对密码进行加密,然后使用user().save()保存到数据库中。

创建用户注册视图

在「accounts」文件夹的「views.py」中添加用户注册的处理。
从django.shortcuts导入render、redirect ←添加redirect
从django.core.exceptions导入ValidationError
从.导入forms
在render后面添加redirect,并添加用于异常处理的ValidationError,最后导入form。

from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import ValidationError
from . import forms


def signin(request):
    signin_form = forms.SignInForm(request.POST or None)
    if signin_form.is_valid():
        try:
            signin_form.save()
            return redirect('accounts:home')
        except ValidationError as e:
            signin_form.add_error('password', e)
    return render(request,'accounts/signin.html', context={
        'signin_form': signin_form,
    })

在使用 POST 方法发送的数据中,通过 request.POST 接收数据,如果是 GET 方法,则返回 None。
通过 signin_form.is_valid() 进行验证检查,并执行在表单中定义的 clean 方法。

通过try语句来执行异常处理,并使用signin_form.save()来执行form中定义的save方法。此时,如果在SignInForm中定义的save方法的validate_password中出现验证错误,那么会调用except部分并通过signin_form.add_error(‘password’, e)将错误传递给表单的password字段。

如果完全实现,则使用重定向进行转移。

登录

创建登录表单

在「accounts」文件夹的「forms.py」中添加一个用于登录的表单。

class LoginForm(forms.Form):
    email = forms.EmailField(label="メールアドレス")
    password = forms.CharField(label="パスワード", widget=forms.PasswordInput)

在登录表单中,我们不会将数据保存到数据库,因此我们继承了forms.Form。
由于本次登录要使用电子邮件地址,所以我们定义了电子邮件地址和密码的字段。

创建登录视图

从django.contrib.auth中导入authenticate和login函数,从django.contrib中导入messages模块。
authenticate函数用于对用户进行身份验证,login函数用于执行登录操作。
messages模块用于在登录后或登录失败时显示消息。

from django.contrib.auth import authenticate, login


def user_login(request):
    login_form = forms.LoginForm(request.POST or None)
    if login_form.is_valid():
        email = login_form.cleaned_data.get('email')
        password = login_form.cleaned_data.get('password')
        user = authenticate(email=email, password=password)
        if user:
            login(request, user)
            messages.success(request, 'ログインしました。')
            return redirect('accounts:home')
        else:
            message.warning(request, 'メールアドレスかパスワードが間違っています。')
        return render(request, 'accounts/login.html', context={
            'login_form': login_form,
        })

user = authenticate(email=email, password=password)
if user is not None:
login(request, user)
messages.success(request, ‘ログインしました。’)

<div class="message">
    {% if messages %}
        {% for message in messages %}
            <div class="alert alert-{{ message.tags }}">
                {{ message.message }}
            </div>
        {% endfor %}
    {% endif %}
</div>
スクリーンショット 2023-02-13 13.28.42.png

退出登录

创建用于登出的视图

从django.contrib.auth导入authenticate,login,logout ⬅︎ 添加logout
从django.contrib.auth.decorators导入login_required
login_required用于判断用户是否已登录。作为logout函数的修饰符,如果用户未登录,则不执行函数。

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required


@login_required
def user_logout(request):
    logout(request)
    messages.success(request, 'ログアウトしました。')
    return redirect('accounts:home')

通过`logout(request)`来执行注销操作。

bannerAds