Django
nginx
PostgreSQL
uwsgi
docker

Djangoでユーザー登録機能を実装する2

前回の続きです。環境、設定、手順等は以下を参照してください。
1. DockerによるDjango(1.11.2)の開発環境構築(Ubuntu:16.04 + Nginx + uWSGI + PostgreSQL)
2. Djangoでログイン認証用アプリケーションを作成
3. Djangoでユーザー登録機能を実装する1


今回は、django.contrib.auth.forms.UserCreationForm を継承した CustomUserCreationForm クラスを作成して、ユーザー登録機能を実装します。
(django.contrib.auth.forms.UserCreationForm の定義場所 → /usr/local/lib/python3.5/dist-packages/django/contrib/auth/forms.py)


まず、accounts/forms.py を作成。

# touch accounts/forms.py

UserCreationForm を継承した CustomUserCreationForm クラスを定義し、3つのクラス変数 username、password1、password2 を変更する。

accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _

password = forms.RegexField(
    max_length=16,
    min_length=8,
    regex=r'^[a-zA-Z][a-zA-Z0-9]+$',
    error_messages={
        'invalid': _('先頭を半角英字から始めて、8〜16文字の半角英数字で入力してください。'),
    },
    widget=forms.PasswordInput,
)

class CustomUserCreationForm(UserCreationForm):
    username = forms.RegexField(
        max_length=8,
        min_length=3,
        regex=r'^[a-z][a-zA-Z0-9]+$',
        error_messages={
            'invalid': _('先頭を小文字の半角英字から始めて、3〜8文字の半角英数字で入力してください。'),
        },
    )
    password1 = password
    password2 = password
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = (
            'username',
            'email',
        )

    def clean_email(self):
        email = self.cleaned_data['email']
        try:
            User._default_manager.get(email=email)
        except User.DoesNotExist:
            return email
        raise forms.ValidationError(
            '同じメールアドレスが既に登録済みです。'
        )

上記以外にも label や help_text などの設定が可能。詳しくは、継承元の django.contrib.auth.forms.UserCreationForm クラスが参考になると思います。


次に、accounts/views.py を更新。

accounts/views.py
from django.contrib.auth.decorators import login_required
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render

from .forms import CustomUserCreationForm

@login_required
def index(request):
    return render(request, 'accounts/index.html')

def new(request):
    form = CustomUserCreationForm()
    return render(request, 'accounts/new.html', {'form': form,})

def create(request):
    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('./login')
        return render(request, 'accounts/new.html', {'form': form,})
    else:
        raise Http404


uWSGI をリロード。

# touch reload.trigger


「localhost:8080/accounts/new」にアクセスし、ユーザー作成やバリデーションが正しく機能していれば OK。


ついでに、accounts/index ページを、汎用ビューを使って更新します。


まず、accounts/urls.py を更新。

accounts/urls.py
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required

from . import views


app_name = 'accounts'
urlpatterns = [
    url(r'^$', login_required(views.IndexView.as_view()), name='index'),
    url(r'^new$', views.new, name='new'),
    url(r'^create$', views.create, name='create'),
    url(r'^login$', auth_views.login, {'template_name': 'accounts/login.html'}, name='login'),
    url(r'^logout$', auth_views.logout, name='logout'),
]

汎用ビューを使う場合、上記のように urls.py に login_required を設定します。


accounts/views.py を更新。

accounts/views.py
from django.contrib.auth.models import User
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render
from django.views import generic

from .forms import CustomUserCreationForm

class IndexView(generic.ListView):
    template_name = 'accounts/index.html'

    def get_queryset(self):
        if self.request.user.is_superuser:
            return User.objects.all().order_by('id')
        else:
            return User.objects.filter(pk=self.request.user.id)

def new(request):
    form = CustomUserCreationForm()
    return render(request, 'accounts/new.html', {'form': form,})

def create(request):
    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('./login')
        return render(request, 'accounts/new.html', {'form': form,})
    else:
        raise Http404


accounts/templates/accounts/index.html を更新。

accounts/templates/accounts/index.html
{% if user_list %}
    <table>
        <thead>
            <tr>
                <th>id</th><th>username</th><th>is_superuser</th><th>last_login</th>
            </tr>
        </thead>
        <tbody>
            {% for user in user_list %}
                <tr>
                    <td>{{ user.id }}</td><td>{{ user.username }}</td><td>{{ user.is_superuser }}</td><td>{{ user.last_login }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endif %}


uWSGI をリロード。

# touch reload.trigger


今回更新した accounts/index ページは、ログインしたユーザーによって以下のように表示内容が切り替わります。

スーパーユーザーでログイン → 全ユーザーの一覧が表示
スーパーユーザー以外でログイン → ログインしたユーザー情報のみ表示