ホーム >  Python >  ユーザ登録(Django)

投稿日:   |  最終更新日:

ユーザ登録(Django)

Python

Vagrantで作ったCentOS7のAnaconda・Django環境に、ユーザ登録ページを作成します。

ユーザ登録ページ

前回、自作のログインページを作りました。今回は、以下のようなユーザ登録ページを作ります。

トップページ(/index) ドメイン直下のページです。ログイン前はページタイトルのみですが、ログインすると、ヘッダーナビゲーションにようこそ○○さんと表示します。
プロフィール(/profile) ログインているユーザ(自分自身)の情報を表示します。ログイン前の状態の場合、ログインページへ遷移します。
ログイン(/login) ユーザ名とパスワードを入力してログインします。ログインが完了すると、ログイン状態になってトップページへ遷移します。
ログアウト(/logout) ログアウト状態にしてトップページへ遷移します。
ユーザ登録(/regist) ユーザ登録をします。登録が完了すると、ログイン状態にしてトップページへ遷移します。

モデルはDjangoに標準で用意されたUserモデルを使います。よってモデルは特に変更しません。

仕様

①トップページです。「ドメイン/」にアクセスします。

ユーザ登録ページです。「ドメイン/regist」へアクセスできます。

ログインページです。「ドメイン/login」にアクセスします。

ログインページからログインした場合は「ドメイン/」(トップページ)へ遷移します。

プロフィールページです。「ドメイン/profile」にアクセスします。ログイン中のユーザの情報を表示します。

ログアウトを押すと、ログアウト処理後トップページへリダイレクトします。

準備

Vagrantでゲスト環境(仮想環境)を作ります。

①Virtualboxをインストールします。Virtualboxのインストールまでで結構です。

VirtualBoxをインストールする for Ubuntu

②Vagrantをインストールします。centos7環境を作りますので、Vagrantのインストールのみ済ませてください。

Vagrantをインストールしてテスト環境を作る for Ubuntu

Vagrantのcentos7環境の詳細を調べる場合は以下のように確認します。

VagrantのCentOS7の環境を確認(lsb_releaseコマンドなど)

③バージョン管理ツールのpyenvインストールします。Anacondaインストールに使います。

VagrantのCentOS7にバージョン管理ツールをインストール(pyenv)

④Anaconda・Djangoインストールします。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(Anaconda・Djangoインストール)

⑤mariadb、mod_wsgiをインストールし、apacheで動作するように設定します。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(MariaDBのインストール・設定)

⑥管理画面(admin)にCSSを適用します。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(管理画面のCSS)

⑦Bootstrapをインストールします。

VagrantのDjangoで作るWebアプリケーション(その6 Bootstrapのインストール)

⑧自作のログインページを作成します。

自作のログインページ(Django)

ホスト環境

OS Ubuntu 16.04.1 LTS 64bit
Virtualbox 5.1
Vagrant 1.9.5

ゲスト環境

OS CentOS 7.1.1503
pyenv 1.1.3-5-g7dae197
Anaconda 3-4.3.0
MariaDB 5.5.52-1.el7
Apache 2.4.6
mod_wsgi 4.5.14

Vagrantへログイン

①【ホスト環境】端末を開き、前回構築したVagrantのディレクトリまで移動します。

cd vagrant/django_apps/

②【ホスト環境】仮想マシンを起動します。

vagrant up

③【ホスト環境】ログインします。

vagrant ssh

プロジェクトの設定

プロジェクトディレクトリを「pj」、アプリケーションディレクトリを「app1」とします。

①rootにログインします。

su -
パスワード:vagrant

②settings.pyに設定を追記します。

cd /home/django/
vi pj1/pj1/settings.py

以下のように編集します。

LOGIN_URL = '/login/'  # ログイン画面のURL
LOGIN_REDIRECT_URL = '/'  # /loginに直接アクセスした場合のリダイレクト

③urls.pyに、URLの設定をします。

vi pj1/pj1/urls.py

以下のように編集します。

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('app1.urls', namespace = 'app1'))
]

アプリケーションの設定

①urls.pyに、URLの設定をします。

vi pj/app1/urls.py

以下のように編集します。

from django.conf.urls import url
from . import views
from .forms import LoginForm
from django.contrib.auth.views import login,logout


urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^profile/$', views.profile, name='profile'),
    url(r'^regist/$', views.regist, name='regist'),
    url(r'^regist_save/$', views.regist_save, name='regist_save'),

    url(r'^login/$', login,
        {'template_name': 'login.html', 'authentication_form': LoginForm},
        name='login'),

    url(r'^logout/$', logout,
        {'template_name': 'index.html'},
        name='logout'),

]

ログイン処理は「django.contrib.auth.views.login」に、ログアウト処理は「django.contrib.auth.views.logout」に任せます。

template_nameには、ログイン・ログアウト後のtemplateを渡します。今回はトップページに遷移しますので「index.html」を記述します。

Django1.10から、url()に直接「django.contrib.auth.views.login」を記述すると、「view must be a callable or a list/tuple in the case of include().」エラーが出ますので注意が必要です。

・・・省略・・・
from django.contrib.auth.views import login,logout
・・・省略・・・
    url(r'^login/$', login,
        {'template_name': 'login.html', 'authentication_form': LoginForm},
        name='login'),

    url(r'^logout/$', logout,
        {'template_name': 'index.html'},
        name='logout'),

②「pj1/app1/models.py」は、今回編集しません。ユーザ登録は、Djangoに標準で用意されたUserモデルを使います。

③アプリケーションディレクトリのforms.pyを編集します。

vi pj1/app1/forms.py

以下のように編集します。

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.forms import AuthenticationForm

class RegisterForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].widget.attrs['class'] = 'form-control'
        self.fields['password1'].widget.attrs['class'] = 'form-control'
        self.fields['password2'].widget.attrs['class'] = 'form-control'

class LoginForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       self.fields['username'].widget.attrs['class'] = 'form-control'
       self.fields['password'].widget.attrs['class'] = 'form-control'

RegisterFormは登録用のフォームです。UserCreationFormを継承することで、Userモデルを使ったユーザ登録を作ります。

form-controlは、Bootstrapを使用するためのクラスの指定です。※他にも指定方法はあります。

class RegisterForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].widget.attrs['class'] = 'form-control'
        self.fields['password1'].widget.attrs['class'] = 'form-control'
        self.fields['password2'].widget.attrs['class'] = 'form-control'

django.contrib.auth.views.loginは、デフォルトでAuthenticationFormを使います。ログインは、AuthenticationFormを継承したフォームを作り、ユーザ名とパスワードのhtmlタグのclassを変更しているだけです。django.contrib.auth.views.loginに「’authentication_form’: LoginForm」と渡せばログインフォームができます。

class LoginForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       self.fields['username'].widget.attrs['class'] = 'form-control'
       self.fields['password'].widget.attrs['class'] = 'form-control'

③アプリケーションディレクトリのviews.pyを編集します。

vi pj1/app1/views.py

以下のように編集します。

from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.http import require_POST
from .forms import RegisterForm

def index(request):
    context = {
        'user' : request.user,
    }
    return render(request, 'index.html', context)


@login_required
def profile(request):
   context = {
       'user': request.user,
   }
   return render(request, 'profile.html')

def regist(request):
    form = RegisterForm(request.POST or None)
    context = {
        'form': form,
    }
    return render(request, 'regist.html', context)

@require_POST
def regist_save(request):
    form = RegisterForm(request.POST)
    if form.is_valid():
        form.save()
        return redirect('app1:index')

    context = {
        'form': form,
    }
    return render(request, 'regist.html', context)

@login_requiredは、ログインしていない場合は、ログインページへ自動リダイレクトするためのデコレータです。

テンプレートの設定

アプリケーションディレクトリ配下のtemplatesディレクトリへhtmlテンプレートを作成します。

①base.htmlを作成します。base.htmlは、テンプレート共通で使用したいhtmlを記述します。

vi pj1/app1/templates/base.html

以下のように記述します。

{% load staticfiles %}
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="shortcut icon" href="{% static 'main/img/favicon.ico' %}">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <title>ユーザ登録</title>

    <!-- Bootstrap -->
    <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-reboot.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-grid.min.css' %}" rel="stylesheet">
    <style>
      .my-form {
        width: 640px;
        margin: 0 auto;
      }

      @media screen and (max-width: 768px) {
        .my-form {
          width: 100%;
        }
      }

      .errorlist li {
        list-style-type: none;
      }

      .errorlist {
        color: red;
        margin-left: 0;
        padding-left: 0;
      }
    </style>
  </head>

  <body>
    <nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse">
      <button class="navbar-toggler navbar-toggler-right"
      type="button" data-toggle="collapse" data-target="#navbarNav"
      aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
      </button>
      <a class="navbar-brand" href="#">App1</a>
      <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
          <li class="nav-item active">
            <a class="nav-link" href="{% url 'app1:index' %}">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{% url 'app1:profile' %}">プロフィール</a>
          </li>
        </ul>
        </ul>
        <ul class="nav navbar-nav ml-auto">

          {% if user.is_authenticated %}
          <li class="nav-item" style="margin-right: 40px;">
            <span class="navbar-text">ようこそ {{  user.get_username }}さん</span>
          </li>
          {% endif %}
          <li class="nav-item">
            <a class="nav-link" href="{% url 'app1:login' %}">ログイン</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{% url 'app1:logout' %}">ログアウト</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{% url 'app1:regist' %}">ユーザ登録</a>
          </li>
        </ul>
      </div>
    <div class="container" style="margin-top: 60px;">
      {% block content %}
      {% endblock %}
    </div>
    <!-- Bootstrap -->
    <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-reboot.min.css' %}" rel="stylesheet">
    <link href="{% static 'css/bootstrap-grid.min.css' %}" rel="stylesheet">
    <!-- js -->
    <script src="{% static 'js/bootstrap.min.js' %}"></script>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </body>
</html>

②index.htmlを作成します。

vi pj1/app1/templates/index.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}
<h1>トップページ</h1>
{% endblock %}

③profile.htmlを作成します。

vi pj1/app1/templates/profile.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}
user.username(名前) : {{ user.username }}<hr>
user.is_staff(/adminにログインできるか) : {{ user.is_staff }}<hr>
user.is_active(アカウントはアクティブか、通常のログインはできるか) : {{ user.is_active }}<hr>
user.is_superuser(すうぱあゆうざあ ですか) : {{ user.is_superuser }}<hr>
user.last_login(最期のログイン) : {{ user.last_login }}<hr>
user.date_joined(アカウントの作られた日) : {{ user.date_joined }}
{% endblock %}
  • ここには、”user”: request.user とcontextを渡しています。
  • request.userは、ログインしてれば、ログインしているユーザのUserモデルのオブジェクトを返します。
  • is_staffなど、Userモデルが持っている属性をいくつか書き出しています。
  • Userモデル(正確には継承しているAbstractUser)のis_staffはデフォルトでFalseです。Falseの場合、「/admin」の管理サイトへアクセスできません。

④login.htmlを作成します。

vi pj1/app1/templates/login.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}

<form class="my-form" action="{% url 'app1:login' %}" method="POST">
  <div class="form-group">
    <label for="id_username">ユーザネーム</label>
    {{ form.username }}
    {{ form.username.errors }}
  </div>

  <div class="form-group">
    <label for="id_password">パスワード</label>
    {{ form.password }}
    {{ form.password.errors }}
  </div>

  <div class="form-group">
    <div>
      <input type="submit" class="btn btn-default" value="ログイン">
    </div>
  </div>

  <input type="hidden" name="next" value={{ next }} />
  {% csrf_token %}

</form>
{% endblock %}
  • <input type=”hidden” name=”next” value={{ next }} />と記述すると、@login_requiredでログインページに飛ばされても、ログイン後に元のページに戻れます。
  • 「action=”{% url app1:login’ %}”」(django.contrib.auth.views.login) で、ログイン処理を行います。

⑤regist.htmlを作成します。

vi pj1/app1/templates/regist.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}

<form class="my-form" action="{% url 'app1:regist_save' %}" method="POST">
  <div class="form-group">
    <label for="id_username">ユーザネーム</label>
    {{ form.username }}
    {{ form.username.errors }}
    <p class="help-block">{{ form.username.help_text }}</p>
  </div>

  <div class="form-group">
    <label class="control-label" for="id_password1">パスワード</label>
    {{ form.password1 }}
    {{ form.password1.errors }}
  </div>

  <div class="form-group">
    <label control-label" for="id_password2">パスワード(確認)</label>
      {{ form.password2 }}
      {{ form.password2.errors }}
      <p class="help-block">{{ form.password2.help_text }}</p>
  </div>

  <div class="form-group">
    <div>
      <input type="submit" class="btn btn-default" value="登録">
    </div>
  </div>
  {% csrf_token %}
</form>
{% endblock %}
トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター、フロントエンドエンジニア 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 20

最近の投稿
人気記事
カテゴリー
広告