ここではユーザが自身でユーザ登録できるような機能を実装します.
まず,Django contrib の auth にある forms.py から class UserCreationForm(forms.ModelForm):
をコピーし,僅かな編集を施します.
users/forms.py
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
"password_mismatch": _("The two password fields didn’t match."),
}
password1 = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput(attrs={"autocomplete": "new-password", 'class': 'form-control'}),
strip=False,
help_text=_("Enter the same password as before, for verification."),
)
class Meta:
model = UserModel
fields = ("username",)
field_classes = {"username": UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self._meta.model.USERNAME_FIELD in self.fields:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs[
"autofocus"
] = True
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError(
self.error_messages["password_mismatch"],
code="password_mismatch",
)
return password2
def _post_clean(self):
super()._post_clean()
# Validate the password after self.instance is updated with form data
# by super().
password = self.cleaned_data.get("password2")
if password:
try:
password_validation.validate_password(password, self.instance)
except ValidationError as error:
self.add_error("password2", error)
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
ユーザ登録のための URL を定義します.
users\urls.py
from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
path('', views.users_index, name='index'),
path('<int:user_id>/', views.users_profile, name='profile'),
path('<int:user_id>/update/', views.users_update, name='update'),
path('login/', views.LoginView.as_view(), name='login'),
path('logout/', views.LogoutView.as_view(), name='logout'),
path('password/', views.PasswordChangeView.as_view(), name='password_change_form'),
path('password_change_done/', views.PasswordChangeDoneView.as_view(), name='password_change_done'),
# ユーザ登録
path('create/', views.UserCreateView.as_view(), name='create'),
# パスワードリセットのメール送信画面
path('password_reset/', views.PasswordResetView.as_view(), name='password_reset'),
# メール送信後の画面
path('password_reset/done/', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
# メールリンクから呼び出される
path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset/done/', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
続いて views.py を編集します.
users/views.py
from urllib.parse import urlparse, urlunparse
from django.conf import settings
# Avoid shadowing the login() and logout() views below.
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.contrib.auth import login as auth_login
from django.contrib.auth import logout as auth_logout
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.decorators import login_required
# from django.contrib.auth.forms import (
# AuthenticationForm,
# PasswordChangeForm,
# PasswordResetForm,
# SetPasswordForm,
# )
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.http import HttpResponseRedirect, QueryDict
from django.shortcuts import resolve_url
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect
from django.urls import reverse
from django.contrib import messages
from django.views.generic import CreateView
# from django.shortcuts import redirect
# from django.urls import reverse
from .forms import UserForm
from .forms import AuthenticationForm
from .forms import PasswordChangeForm
from .forms import SetPasswordForm
from .forms import PasswordResetForm
from .forms import UserCreationForm
UserModel = get_user_model()
...(中略)...
class UserCreateView(CreateView):
template_name = 'users/create_form.html'
form_class = UserCreationForm
def form_valid(self, form):
messages.success(self.request, 'ユーザ登録しました')
user = form.save()
return HttpResponseRedirect("/")
ユーザ登録ページの HTML を作成します.
users/templates/users/create_form.html
{% extends "base.html" %}
{% block title %}
ユーザ登録
{% endblock %}
{% block content %}
<h1 class="my-5">コメントアプリケーション</h1>
<div class="card">
<div class="card-header">ユーザ登録</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary btn-block">
ユーザ登録
</button>
</form>
</div>
<div class="card-footer">
<p>
</p>
</div>
</div>
{% endblock content %}
ログイン前の Navbar にユーザ登録のリンクを作成します.
comments/templates/base.html
{% if user.is_authenticated %}
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ user.username }}
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'users:profile' user.id %}">Profile</a></li>
<li><a class="dropdown-item" href="{% url 'users:update' user.id %}">Edit Profile</a></li>
<li><a class="dropdown-item" href="{% url 'users:password_change_form' %}">Change Password</a></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{% url 'users:logout' %}">ログアウト</a></li>
</ul>
</li>
</ul>
{% else %}
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'users:create' %}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'users:index' %}">Login</a>
</li>
</ul>
{% endif %}
ログイン前のトップページに Register リンクが表示されるようになりました.この Register をクリックします.
ユーザ名とパスワードを設定してユーザ登録します.
登録できれば次の画面に移動します.
いま作成したユーザ名でログインやログアウトができることを確認してください.