Python Django入門 初めの1歩からWEBアプリ作成までの流れ その13 ユーザー登録機能の実装(AbstractUser編)

みなさんこんにちは、ZeroTerasu(@ZeroTerasu)です。

 Djangoでユーザー登録機能を実装する方法の2回目の今回は、「②”AbstractUser”モデルを継承する方法」を解説します。AbstractUserモデルを継承してカスタムユーザークラスを作成します。Django公式ドキュメントでもカスタムユーザーの使用が推奨されています。

 因みに、第1回の「①Djangoデフォルトの”User”を使用する方法」ではフィールドの追加・削除が難しいため、これらの操作をする場合は今回の記事が参考になると思います。

尚、今回は下記の設定で進めていきます。

プロジェクト名とアプリ名

プロジェクト名=”pj”

アプリ名=”registration”

今回の内容はこちらです。

今回の内容
ポイント①:AbstractUserモデルを継承してカスタムユーザーを作成。
ポイント②:settings.pyで”AUTH_USER_MODEL”の設定。
ポイント③:UserCreationFormを継承してフォームを作成。
ポイント④:CreateView を継承してユーザー登録機能ビューを作成。
ポイント➄:URLパターンの設定。ログイン必須ページには、ビューにlogin_required()をデコレートする。
ポイント⑥:テンプレートの作成

アプリの概要説明

アプリの内容

下記のような流れでユーザー登録機能を実装していきます。

①トップページからユーザー登録ページへ移動。

②ユーザー登録とログインを同時に実行する。

③ログイン後ページに遷移する。

トップページ

・トップページには「登録ページ」と「ログイン後ページ」のリンク先を設定します。

ログイン後ページ(ログインしていない状態で、ログイン後に遷移するページにアクセスした場合)

・仮にログインしていない状態でログイン後ページにアクセスしようとするとエラーが表示されるようにしています。

登録ページ

・forms.pyでSignUpForm内に設定したフィールドが表示されるようになっています。

登録・ログイン成功ページ

・ユーザー登録が無事に完了した後、自動的にログインされ、フォームに入力したデータがテンプレートに渡され表示されます。

ポイント①:AbstractUserモデルを継承してカスタムユーザーを作成。

models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.
class User(AbstractUser):
    # 1.フィールドの修正:フィールドをオーバライド。
    email = models.EmailField(verbose_name='メールアドレス', unique=False, blank=True)
    # 2.フィールドの追加
    gendar = models.CharField(verbose_name='性別',max_length=10)
    favorite_url = models.URLField(verbose_name='お気に入りURL', max_length=300, blank=True, null=True)
    # ユーザー作成時に必須となるフィールドのリストを指定
    REQUIRED_FIELDS = ['gendar']

1. フィールドの修正方法:既存のフィールドをオーバーライド

2. フィールドの追加方法:新規フィールドを追加

※ 必須フィールドの指定:REQUIRED_FIELDSの指定

ポイント②:settings.pyで”AUTH_USER_MODEL”の設定。

settings.py
# 変更箇所-1
INSTALLED_APPS = [
    'registration', #<=追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

# 変更箇所-2
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'], #<=追加
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# 変更箇所-3
LANGUAGE_CODE = 'ja' #<=デフォルトでは、'en-us'になっていますが、日本語に変更します。

# 変更箇所-4
AUTH_USER_MODEL = 'registration.User'

ポイント③:UserCreationFormを継承してフォームを作成。

forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model

User = get_user_model()
GENDER_CHOICES = [
    # 最初の要素が実際の値、2番目の要素が表示されるラベルです。
    ('男性', '男性'),
    ('女性', '女性'),
    ('その他', 'その他')
]

class SignUpForm(UserCreationForm):
    gendar = forms.ChoiceField(label='性別',choices=(GENDER_CHOICES))
    class Meta:
        model=User
        fields = ['username', 'email', 'password1', 'password2', 'gendar', 'favorite_url']
UserCreationForm

UserCreationFormは、Djangoが提供するデフォルトのフォームクラスの1つです。このフォームは、ユーザーの新規登録(ユーザー作成)に使用されます。UserCreationFormは、ユーザー名パスワードパスワードの確認など、一般的なユーザー作成に必要なフィールドを提供します。

UserCreationFormはデフォルトでユーザーモデル(User)を対象としています。カスタムユーザーモデルを使用している場合は、それに合わせてフォームをカスタマイズする必要があります。(別記事にて解説致します。)

UserCreationFormの主要フィールド一覧

username: ユーザー名を入力するフィールドです。入力必須項目です。一意である必要があります。(他のユーザーとこのフィールド名が被ってはいけません。)

email: メールアドレスを入力するフィールドです。入力は任意です。

password1: パスワードを入力するフィールドです。パスワードはセキュアにハッシュ化され保存されます。

password2: パスワードを再入力するフィールドです。このフィールドはpassword1と一致する必要があります。

・fieldsには、リスト形式またはタプル形式で使用するフィールドを渡します。

・必要に応じて独自のフィールドを追加することもできます。カスタムフィールドを追加する場合は、UserCreationFormを継承し、新しいフィールドを追加するクラスを作成することができます。

ポイント④:CreateView を継承してユーザー登録機能ビューを作成。

views.py
from django.shortcuts import render
from django.http.response import HttpResponseRedirect
from django.views.generic import TemplateView
from django.views.generic.edit import CreateView
from .forms import SignUpForm
from django.contrib.auth import login
from django.urls import reverse_lazy
from django.contrib.auth import get_user_model

# Create your views here.
class IndexView(TemplateView):
    template_name='registration/index.html'

class HomeView(TemplateView):
    template_name='registration/home.html'

class SignUpView(CreateView):
    form_class=SignUpForm # form_class属性は、ビューで使用されるフォームクラスを指定します。この例では、'SignUpForm'というフォームクラスが使用されます。
    template_name='registration/signup.html' # template_name属性は、ビューで使用されるテンプレートのパスを指定します。この例では、'app/signup.html'というテンプレートが使用されます。
    success_url=reverse_lazy('registration/home.html') # success_url属性は、フォームの送信後にリダイレクトされるURLを指定します。reverse_lazy()関数を使用して逆引き解決されたURLを指定しています。この例では、'app/home.html'というURLにリダイレクトされます。

    def form_valid(self, form):
        # form.save()メソッドを使用してフォームのデータを保存し、新しいユーザーオブジェクトを取得します。
        user=form.save()
        # login()関数を使用して、self.requestオブジェクトと保存されたユーザーオブジェクトを使用してユーザーをログインさせます。
        login(self.request, user) 
        # self.object属性に保存されたユーザーオブジェクトを設定します。これにより、ビュー内でユーザーオブジェクトにアクセスできます。
        self.object = user
        # get_success_url()メソッドを使用してリダイレクト先のURLを取得し、HttpResponseRedirectを使用してそのURLにリダイレクトします。
        return HttpResponseRedirect(self.get_success_url())
コード解説

 上記のビューでは、ユーザーの新規登録を処理し、登録後にユーザーをログインさせて指定されたURLにリダイレクトさせています。

 まず、CreateViewを継承してSignUpViewというクラスを定義し、ユーザーの新規登録ログインを処理します。

form_valid(self, form): form_valid()メソッドは、フォームのデータが有効である場合に呼び出されます。このメソッドでは、フォームのデータを保存し、ユーザーをログインさせてリダイレクトする処理が行われます。

ポイント➄:URLパターンの設定。ログイン必須ページには、ビューにlogin_required()をデコレートする。

pj/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('registration.urls')),
    path('admin/', admin.site.urls),
]
pj/registration/urls.py
from django.urls import path
from . import views
from django.contrib.auth.decorators import login_required

urlpatterns = [
    path('', views.IndexView.as_view(), name='registration/index'),
    path('signup/', views.SignUpView.as_view(), name='registration/signup'),
    path('home/', login_required(views.HomeView.as_view()), name='registration/home'),
]
コード解説

・ログイン必須ページには、login_required()メソッドを使い、対象のviewを引数として内包する。

ポイント⑥:テンプレートの作成

①トップページ:index.html → ②登録ページ:signup.html → ③ログイン後ページ:home.html

pj/templates/registration/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    <div style="margin: 0 auto; width: 1100px;">
        <h1>トップページ</h1><br>
        <a href="{% url 'registration/signup' %}">ユーザー登録ページのリンク先です。</a><br>
        <a href="{% url 'registration/home' %}">ログイン後ページのリンク先です。(ログインしていない状態では入れません。)</a>
    </div>
</body>
</html>
pj/templates/registration/signup.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>signup</title>
</head>
<body>
    <div style="margin: 0 auto; width: 1100px;">
        <h1>登録フォーム</h1>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <input type="submit" value="登録">
        </form>
    </div>
</body>
</html>
pj/templates/registration/home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
</head>
<body>
    <div style="margin: 0 auto;">
        <h1>ユーザー詳細ページ</h1>
        <table border="1" rule="all" style="border: 1px solid black; border-collapse: collapse;">
            <tr>
                <th>username</th>
                <th>email</th>
                <th>gendar</th>
                <th>favorite_url</th>
            </tr>
            <tr>
                <td>{{ user.username }}</td>
                <td>{{ user.email }}</td>
                <td>{{ user.gendar }}</td>
                <td>{{ user.favorite_url }}</td>
            </tr>
        </table>
    </div>
</body>
</html>

コメント

タイトルとURLをコピーしました