web-dev-qa-db-ja.com

Django 2-確認メールとCBVを使用してユーザーを登録する方法は?

この質問は、特にregistrationモジュールが(まだ)利用できないため、Django 2.0の回答を目指しています。

さらに、これは広範に思えるかもしれませんが、私はサードパーティのモジュールを使用できない状況にいることがよくあります。ここから取得した情報を探してまとめるか、Django docsは頭痛の種でした。


ワークフロー:

次のフローが必要だとしましょう:

  1. ユーザーはサインアップページに移動し、次のフィールドに入力します:first_namelast_nameおよびemail(メールはユーザー名として使用されます)。
  2. ユーザーはフォームを送信し、一意のトークンを含むURLが記載された確認メールを受信します。
  3. ユーザーが受信したリンクをクリックすると、パスワードを設定するページにリダイレクトされます。完了すると、彼はダッシュボードページにログインしています。

追加情報:ユーザーは後で電子メール(実際にはユーザー名)とパスワードを使用してログインします。


具体的な質問:

  • モデル/ビュー(CBVを使用)/フォーム/ URLはどのように見えますか?
12
Cajuu'

ユーザーモデル

まず、カスタムUserモデルとカスタムUserManagerを作成してusernameフィールドを削除し、代わりにemailを使用する必要があります。

_models.py_では、UserManagerは次のようになります。

_from Django.contrib.auth.models import BaseUserManager


class MyUserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """
    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The Email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
_

Userモデル:

_from Django.db import models
from Django.contrib.auth.models import AbstractBaseUser
from Django.contrib.auth.models import PermissionsMixin
from Django.utils.translation import ugettext_lazy as _


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, null=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    USERNAME_FIELD = 'email'
    objects = MyUserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
return self.email
_

そして最後に_settings.py_で:

_AUTH_USER_MODEL = ‘your_app_name.User’
_

トークンジェネレーター

2番目の部分は、メール確認URLのトークンジェネレーターを作成することです。組み込みのPasswordResetTokenGeneratorを継承して、簡単にすることができます。

_tokens.py_を作成:

_from Django.contrib.auth.tokens import PasswordResetTokenGenerator
from Django.utils import six

class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )

account_activation_token = TokenGenerator()
_

サインアップフォーム

次に、ビューで使用する登録フォームを作成する必要があります。最適な方法は、組み込みのDjangoのUserCreationFormを継承し、usernameおよびpasswordフィールドを削除してからemailフィールドを追加することです。 _forms.py_:

_from Django import forms
from Django.contrib.auth.forms import UserCreationForm
from Django.contrib.auth.models import User

class SignupForm(UserCreationForm):
    email = forms.EmailField(max_length=200, help_text='Required')

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name')
_

サインアップビュー

サインアップでは、ユーザーがアクティベーションを完了するまで、ユーザーをパスワードなしset_unusable_password()で非アクティブにする_user.is_active = False_にする必要があります。また、アクティベーションURLを作成し、登録完了後にユーザーにメールで送信します。

_views.py_で:

_from Django.views import View
from Django.http import HttpResponse
from Django.shortcuts import render
from .forms import SignupForm
from Django.contrib.sites.shortcuts import get_current_site
from Django.utils.encoding import force_bytes
from Django.utils.http import urlsafe_base64_encode
from .tokens import account_activation_token
from Django.core.mail import EmailMessage


class Signup(View):
    def get(self, request):
        form = SignupForm()
        return render(request, 'signup.html', {'form': form})

    def post(self, request):
        form = SignupForm(request.POST)
        if form.is_valid():
            # Create an inactive user with no password:
            user = form.save(commit=False)
            user.is_active = False
            user.set_unusable_password()
            user.save()

            # Send an email to the user with the token:
            mail_subject = 'Activate your account.'
            current_site = get_current_site(request)
            uid = urlsafe_base64_encode(force_bytes(user.pk))
            token = account_activation_token.make_token(user)
            activation_link = "{0}/?uid={1}&token{2}".format(current_site, uid, token)
            message = "Hello {0},\n {1}".format(user.username, activation_link)
            to_email = form.cleaned_data.get('email')
            email = EmailMessage(mail_subject, message, to=[to_email])
            email.send()
            return HttpResponse('Please confirm your email address to complete the registration')
_

そしてもちろん、サインアップビュー用のテンプレートを作成することを忘れないでください。


アクティベーションビュー

次に、サインアップビューで作成したURLを使用して、ユーザーがアカウントをアクティブにするためのビューを作成する必要があります。また、組み込みのDjangoのSetPasswordFormを使用して、ユーザーがパスワードを設定できるようにします。

_views.py_で:

_from Django.contrib.auth import get_user_model, login, update_session_auth_hash
from Django.contrib.auth.forms import PasswordChangeForm
from Django.utils.encoding import force_bytes, force_text
from Django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from .tokens import account_activation_token

User = get_user_model()

class Activate(View):
    def get(self, request, uidb64, token):
        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None
        if user is not None and account_activation_token.check_token(user, token):
            # activate user and login:
            user.is_active = True
            user.save()
            login(request, user)

            form = PasswordChangeForm(request.user)
            return render(request, 'activation.html', {'form': form})

        else:
            return HttpResponse('Activation link is invalid!')

    def post(self, request):
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user) # Important, to update the session with the new password
            return HttpResponse('Password changed successfully')
_

繰り返しますが、アクティベーションビュー用のテンプレートを作成することを忘れないでください。


URL

最後に、_urls.py_で:

_from . import views
from Django.urls import path

urlpatterns = [
    ...
    path('signup/', views.signup.as_view(), name='signup'),
    path('activate/<str:uid>/<str:token>', views.activate.as_view(), name='activate'),
]
_

追伸正直なところ、私はまだこれらすべての部分を一緒にテストする機会がありませんでしたが、何か問題が起こったかどうかをaskすることをdonしません。

21
Peter Sobhi

Peterの答えに加えて、Django 2を使用している場合、エンコードとデコードの部分は少し異なります。

エンコード:

'uid': urlsafe_base64_encode(force_bytes(user.pk)),を変更

'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),

デコード:

uid = force_text(urlsafe_base64_decode(uidb64))を変更

uid = urlsafe_base64_decode(uidb64).decode()

1
Yogi Bear

パスワードリセットフォームを呼び出して、リクエストからユーザーの電子メールを渡すことができます。組み込みの認証を使用してリンクを送信します。電子メールとパスワードのフォームのデフォルトのテンプレートを置き換えることができます。

from Django.contrib.auth.forms import PasswordResetForm

# either the request or domain_override kwarg is needed
form = PasswordResetForm({'email': user.email})
        if form.is_valid():
            return form.save(
                from_email='[email protected]',
                # domain_override='your_domain',
                request=request, 
                email_template_name='registration/password_reset_email.html'
            )

一時的なダミーのパスワードを作成できるように、これが機能するには既存のパスワードが必要であることを確認してください

password = User.objects.make_random_password()
user.set_password(password)
0
chaggy