3-1. ユーザー登録画面を作成する

今回のテーマは「ユーザー登録画面を作成する」です。まずはユーザー登録画面を作成しましょう。これらの画面(ビュー)はDjangoでは用意されていませんので自作する必要があります。もうDjangoに慣れてきた皆さんなら簡単ですよね?

※本ページは第一章、第二章の続きとして書かれています。省略されたソースコードやプロジェクトの説明がある可能性があります。ご了承下さい。

accountsアプリケーションの作成

まずはユーザー情報を扱うaccountsアプリケーションを作成しましょう。


(venv)$ ./manage.py startapp accounts

例によってaccounts/urls.pyも作成しておきます。

accounts/urls.py


from django.urls import path, include
from . import views

app_name = 'accounts'

urlpatterns = [
]

ひとまずurlpatternsはから配列で作成しておきます。

また、mysite/settings.pyとmysite/urls.pyにも追記をしておきます。
mysite/settings.py(一部抜粋)


  INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'django.contrib.sites',
      'django.contrib.sitemaps',
      'debug_toolbar',
      'base',
      'thread',
      'api',
      'search',
+     'accounts',
  ]

mysite/settings.py(一部抜粋)


  urlpatterns = [
      path('admin/', admin.site.urls),
+     path('accounts/', include('accounts.urls')),
      path('', include('base.urls')),
      path('thread/', include('thread.urls')),
      path('api/', include('api.urls')),
      path('search/', include('search.urls')),
      path('sitemap.xml', sitemap, {'sitemaps': sitemaps}),
  ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

UserCreationFormについて

今回はDjangoに備わっているUserCreationFormを使ってユーザー登録画面を作成していきます。このUserCreationFormはDjango標準の認証機能として搭載されているUserモデルの作成フォームです。Userをカスタマイズする場合はUserCreationFormもカスタマイズする必要が出てきますのでご注意下さい。

UserCreationFormに関しては公式ドキュメントのDjangoの認証システムを使用するをご覧ください。

ユーザー登録画面の作成

まずはユーザー登録画面を作成しましょう。特に難しいことはありません。FormViewを継承したクラスを作り、トピック登録画面と同様に確認画面付きの画面を作成していきます。ただし、今回は単にユーザーを登録するだけではなく、登録と同時に認証してログインする処理も行うことにします。まずテンプレートを用意しましょう。

template/registration/create.html



{% extends 'base/base.html' %}
{% block title %}ITについて切磋琢磨する掲示板 - {{ block.super }}{% endblock %}
{% block content %}
<div class="ui grid stackable">
    <div class="eleven wide column">
        <div class="ui breadcrumb">
            <a href="{% url 'base:top' %}" class="section">TOP</a>
            <i class="right angle icon divider"></i>
            <a class="active section">ユーザー作成</a>
        </div>
        <div class="ui segment">
            <div class="content">
                <div class="header"><h3>ユーザー作成</h3></div>
                <form class="ui form" action="" method="POST">
                    {% csrf_token %}
                    {{form.as_p}}
                    <button class="ui orange button" name="next" value="confirm" type="submit">確認</button>
                </form>
            </div>
        </div>
    </div>
    {% include 'base/sidebar.html' %}
</div>
{% endblock %}

template/registration/create_confirm.html



{% extends 'base/base.html' %}
{% block title %}ITについて切磋琢磨する掲示板 - {{ block.super }}{% endblock %}
{% block content %}
<div class="ui grid stackable">
    <div class="eleven wide column">
        <div class="ui breadcrumb">
            <a href="{% url 'base:top' %}" class="section">TOP</a>
            <i class="right angle icon divider"></i>
            <a class="active section">ユーザー作成</a>
        </div>
        <div class="ui segment">
            <div class="content">
                <div class="header"><h3>ユーザー作成</h3></div>
                <table  class="ui celled table table table-hover" >
                    <tr><td>お名前</td><td>{{form.cleaned_data.username}}</td></tr>
                    <tr><td>パスワード</td><td>********</td></tr>
                </table>
                <form class="ui form" action="" method="POST">
                    {% csrf_token %}
                    {% for field in form %}
                    {{field.as_hidden}}
                    {% endfor %}
                    <button class="ui button" name="next" value="back" type="submit">修正</button>
                    <button class="ui orange button" name="next" value="regist" type="submit">登録</button>
                </form>
            </div>
        </div>
    </div>
    {% include 'base/sidebar.html' %}
</div>
{% endblock %}

ここまでは特に問題ないと思います。ではビューを作っていきましょう。

accounts/views.py


from django.shortcuts import render, redirect
from django.views.generic import TemplateView, FormView
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.contrib.auth import login, authenticate

# Create your views here.

class UserCreateView(FormView):
    form_class = UserCreationForm
    template_name = 'registration/create.html'
    success_url = reverse_lazy('base:top')
    def form_valid(self, form):
        print(self.request.POST['next'])
        if self.request.POST['next'] == 'back':
            return render(self.request, 'registration/create.html', {'form': form})
        elif self.request.POST['next'] == 'confirm':
            return render(self.request, 'registration/create_confirm.html', {'form': form})
        elif self.request.POST['next'] == 'regist':
            form.save()
            # 認証
            user = authenticate(
                username=form.cleaned_data['username'],
                password=form.cleaned_data['password1'],
            )
            # ログイン
            login(self.request, user)
            return super().form_valid(form)
        else:
            # 通常このルートは通らない
            return redirect(reverse_lazy('base:top'))

簡単に解説しますと、POSTで受ける’next’パラメータの値によって挙動がコントロールされているのは問題ないと思います。この仕組みはトピック登録画面と同様です。問題はform_classで設定されているUserCreationFormですね。これはDjangoで用意されたフォームでユーザー登録用のフォームです。今回はこのフォームクラスをそのまま使いました。もし、カスタマイズが必要な場合はUserCreationFormを継承したクラスを作成すれば良いということになります。次に、登録処理のところですね。form.save()メソッドを呼んでユーザー情報を登録してUser情報を登録しています。次にauthenticate関数を呼んで認証処理を行っています。authenticate関数が呼ばれると認証用のバックエンドのリストが呼び出されて順番に認証バックエンドで認証できるかが試されていきます。無事に認証が通れば認証バックエンドと紐づけされたユーザーが返される仕組みです。このユーザーをlogin関数で処理することでセッションにユーザーデータをもたせてログイン処理を行っています。

ではこのビューにアクセスするURLを作成しましょう。
accounts/urls.py


from django.urls import path, include
from . import views

app_name = 'accounts'

urlpatterns = [
    path('create/', views.UserCreateView.as_view(), name="create"),
]

早速確認したいところですが、ここでユーザー登録してログインした際にヘッダー部分の表示が変わるように変更しておきましょう。templates/base/base.htmlを修正します。



  {% load static %}
  <!DOCTYPE html>
  <head>
      <meta charset="UTF-8">
      <meta http-equiv="content-language" content="ja">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
      {% block meta_tag %}{% endblock %}
      <link href="{% static 'css/semantic.css' %}" rel="stylesheet">
      {% block css %}{% endblock %}
      <title>
          {% block title %}IT学習ちゃんねる{% endblock %}
      </title>
  </head>
  <body>
      <div class="ui stackable inverted menu">
          <a href="{% url 'base:top' %}" class="header item">
              IT学習ちゃんねる
          </a>
          <a href="{% url 'base:about' %}" class="item">
              このサイトはなに?
          </a>
          <a class="item" href="{% url 'thread:create_topic' %}">
              トピック作成
          </a>
-         <div class="right menu">
-             <a class="item" href="">ログイン</a>
-             <a class="item" href="">ユーザー登録</a>
-         </div>
+         <div class="right menu">
+             {% if user.is_authenticated %}
+             <a class="item" href="">ユーザー情報</a>
+             <a class="item" href="">ログアウト</a>
+             {% else %}
+             <a class="item" href="">ログイン</a>
+             <a class="item" href="{% url 'accounts:create' %}">ユーザー登録</a>
+             {% endif %}
+         </div>
      </div>
      
      <div class="ui container" style="min-height:100vh;">
          {% block content %}
          {% endblock %}
      </div>
      <div class="ui inverted stackable footer segment">
          <div class="ui container center aligned">
              <div class="ui horizontal inverted small divided link list">
                  <a href="{% url 'base:top' %}" class="item">© 2019 IT学習ちゃんねる(仮)</a>
                  <a href="{% url 'base:terms' %}" class="item">利用規約</a>
                  <a href="{% url 'base:policy' %}" class="item">プライバシーポリシー</a>
              </div>
          </div>
      </div>
      <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
      <script type="text/javascript" src="{% static 'js/semantic.js' %}"></script>
      {% block js %}{% endblock %}
  </body>

ポイントは条件分岐で使用されているuser.is_authenticated関数ですねこれはユーザーが認証されているかを判定する関数です。ユーザーがログインしてに称された状態であれば「ユーザー情報」と「ログアウト」を表示するようにしています。ユーザー登録だけは画面が作成されていますのでURLを設定します。

それでは確認してみましょう。ユーザーを登録してTOPページに遷移してヘッダーの表示が変化すればOKです。
まずはヘッダーの「ユーザー登録」からアクセス

ユーザーを作成

完了するとヘッダーの表示が変化する。(ログイン済み)

最後に

今回は会員サイトを作る上で必須となる会員登録ページの作り方でした。UserCreationFormを使うことで余分な手間なく出来たと思います。次回は登録したユーザーの情報を表示するページを作っていきます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です