Регистрация с подтверждением по почте django

Сделал сброс пароля с помощью email c стандартной формой PasswordResetForm. Можно как то сделать регистрацию с подтверждением по почте с помощью UserCreationForm?

urls.py

urlpatterns = [
    path('personalArea/', views.personalArea, name='personalArea'),

    path('register/', views.register, name="register"),
]

views.py

def register(request):
    if not request.user.is_authenticated:
        if request.POST:
            form = RegistrationForm(request.POST or None)
            if form.is_valid():
                form.save()
                username = form.cleaned_data.get('username')
                my_password1 = form.cleaned_data.get('password1')

                user = authenticate(username=username, password=my_password1)
                if user and user.is_active:
                    login(request, user)
                    return redirect('/personalArea/')
                else:
                    form.add_error(None, 'Unknown or disabled account')
                    return render(request, 'registration/register.html', {'form': form})

            else:
                return render(request, 'registration/register.html', {'form': form})
        else:
            return render(request, 'registration/register.html', {'form': RegistrationForm()})
    else:
        return redirect('/personalArea/')

forms.py

class RegistrationForm(UserCreationForm):
    email = forms.EmailField(required=True, label='Email')
    username = forms.CharField(required=True, max_length=30, label='Логин', min_length=2)
    password1 = forms.CharField(required=True, max_length=30, label='Пароль', min_length=8)
    password2 = forms.CharField(required=True, max_length=30, label='Повторите пароль', min_length=8)
    firstname = forms.CharField(required=True, max_length=25,label='Номер телефона', min_length=10)

    error_messages = {
        'password_mismatch': ("Пароли не совпадают."),
        'error': ("Форма не валидна."),
        'username_exists': _("Пользователь с таким именем уже существует."),
    }

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

    def clean_username(self):
        username = self.cleaned_data.get("username")
        try:
            User._default_manager.get(username=username)
            # if the user exists, then let's raise an error message
            raise forms.ValidationError(
                self.error_messages['username_exists'],  # my error message
                code='username_exists',  # set the error message key
            )
        except User.DoesNotExist:
            return username  # if user does not exist so we can continue the registration process

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        user.first_name = self.cleaned_data['firstname']
        user.password1 = self.cleaned_data['password1']
        user.password2 = self.cleaned_data['password2']

        if commit:
            user.save()
        return user

register.html

{% extends  'base.html' %}
{% load crispy_forms_tags %}
{% load static %}

{% block content %}
{% if not user.is_authenticated %}
<div class="container">
<h1 class="text-center">Регистрация</h1>
    <div class="col-lg-6 col-lg-offset-3">
        <form method="post" action="{% url 'register' %}">
            {% csrf_token %}
            {% for field in form %}
            <p>
              {{ field.label_tag }}<br>
                {% for error in field.errors %}
                    <p class="register-error">{{ error }}</p>
              {% endfor %}
              {{ field }}
              {% if field.help_text %}
              <span class="help-text-register">{{ field.help_text }}</span>
              {% endif %}

            </p>
            {% endfor %}
            <button type="submit" class="btn btn-success">Зарегистрироваться</button>
        </form>
    </div>
</div>
{% else %}
<h1 class="text-center">Вы уже зарегистрированы!</h1>
<h5 class="text-center">Чтобы зарегистрировать новый аккаунт, выйдете из текущего.</h5>
{% endif %}

{% endblock %}

Ответы (2 шт):

Автор решения: Vadim.Sharoikin

пример с отправкой кода на почту для активации.

1 Добавить к модели пользователя code

2 Установить флаг пользователя is_active в False

def generate_code():
    random.seed()
    return str(random.randint(10000,99999))

def register(request):
    if not request.user.is_authenticated:
        if request.POST:
            form = RegistrationForm(request.POST or None)
            if form.is_valid():
                form.save()
                username = form.cleaned_data.get('username')
                my_password1 = form.cleaned_data.get('password1')
                code = generate_code()
                message = code
                user = authenticate(username=username, password=my_password1)
                send_mail('код подтверждения', message,
                settings.EMAIL_HOST_USER,
                ['[email protected]'], 
                fail_silently=False)  
                if user and user.is_active:
                    login(request, user)
                    return redirect('/personalArea/')
                else: #тут добавить редирект на страницу с формой для ввода кода.
                    form.add_error(None, 'Unknown or disabled account')
                    return render(request, 'registration/register.html', {'form': form})

            else:
                return render(request, 'registration/register.html', {'form': form})
        else:
            return render(request, 'registration/register.html', {'form': 
            RegistrationForm()})
    else:
        return redirect('/personalArea/')

#написать обработчик 2 формы 
def endreg(request):
    if request.method == 'POST':
        form = NameForm(request.POST)
        if form.is_valid():
            code_use = form.cleaned_data.get("key")
            user = User.objects.get(code=code_use)
            user.is_active = True
            user.save()
     else:
         form = NameForm1()

Примерно как-то так. Скорее всего endreg функцию предется подправить, но смысл должен быть понятен

→ Ссылка
Автор решения: Artem Welly

В общем сделал работает, есть проблема в том, что код который отсылается сохраняется в базе, его нужно потом как то удалять через время , когда он не активен, иначе будут наложения если вдруг другому пользователю срандомится такой же код, либо нужно как то сделать ссылку отличную от стандартной.Может есть идеи как сделать лучше?

urls.py

urlpatterns = [
    path('personalArea/', views.personalArea, name='personalArea'),
    path('register/', views.register, name="register"),
    path('activation_code_form/', views.endreg, name="endreg"),
    path('',views.activation, name='activation'),
]

views.py

def generate_code():
    random.seed()
    return str(random.randint(10000,99999))

def register(request):
    if not request.user.is_authenticated:
        if request.POST:
            form = RegistrationForm(request.POST or None)
            if form.is_valid():
                form.save()
                username = form.cleaned_data.get('username')
                email = form.cleaned_data.get('email')
                my_password1 = form.cleaned_data.get('password1')
                u_f = User.objects.get(username=username, email=email, is_active=False)
                code = generate_code()
                if Profile.objects.filter(code=code):
                    # for p in Profile.objects.filter(code=code):
                    #     p.delete()
                    code = generate_code()

                message = code
                user = authenticate(username=username, password=my_password1)
                now = datetime.datetime.now()

                Profile.objects.create(user=u_f, code=code, date=now)

                send_mail('код подтверждения', message,
                settings.EMAIL_HOST_USER,
                [email],
                fail_silently=False)
                if user and user.is_active:
                    login(request, user)
                    return redirect('/personalArea/')
                else: #тут добавить редирект на страницу с формой для ввода кода.
                    form.add_error(None, 'Аккаунт не активирован')
                    return redirect('/activation_code_form/')
                    # return render(request, 'registration/register.html', {'form': form})

            else:
                return render(request, 'registration/register.html', {'form': form})
        else:
            return render(request, 'registration/register.html', {'form':
            RegistrationForm()})
    else:
        return redirect('/personalArea/')

def endreg(request):
    if  request.user.is_authenticated:
        return redirect('/personalArea/')
    else:
        if request.method == 'POST':
            form = MyActivationCodeForm(request.POST)
            if form.is_valid():
                code_use = form.cleaned_data.get("code")
                if Profile.objects.filter(code=code_use):
                    profile = Profile.objects.get(code=code_use)
                else:
                    form.add_error(None, "Код подтверждения не совпадает.")
                    return render(request, 'registration/activation_code_form.html', {'form': form})
                if profile.user.is_active == False:
                    profile.user.is_active = True
                    profile.user.save()
                    # user = authenticate(username=profile.user.username, password=profile.user.password)
                    login(request, profile.user)
                    profile.delete()
                    return redirect('/personalArea/')
                else:
                    form.add_error(None, '1Unknown or disabled account')
                    return render(request, 'registration/activation_code_form.html', {'form': form})
            else:
                return render(request, 'registration/activation_code_form.html', {'form': form})
        else:
            form = MyActivationCodeForm()
            return render(request, 'registration/activation_code_form.html', {'form': form})

models.py

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', default=None, on_delete=models.CASCADE)
    code = models.CharField(max_length=50,blank=True, null=True, default=None)
    date = models.DateField(blank=True, null=True)

forms.py

class MyActivationCodeForm(forms.Form):
    error_css_class = 'has-error'
    error_messages = {'password_incorrect':
                          ("Старый пароль не верный. Попробуйте еще раз."),
                      'password_mismatch':
                          ("Пароли не совпадают."),
                      'cod-no':
                          ("Код не совпадает."),}


    def __init__(self, *args, **kwargs):
        super(MyActivationCodeForm, self).__init__(*args, **kwargs)

    code = forms.CharField(required=True, max_length=50, label='Код подтвержения', widget=forms.PasswordInput(attrs={'class': 'form-control'}),  error_messages={'required': 'Введите код!','max_length': 'Максимальное количество символов 50'})



    def save(self, commit=True):
        profile = super(MyActivationCodeForm, self).save(commit=False)
        profile.code = self.cleaned_data['code']

        if commit:
            profile.save()
        return profile

class RegistrationForm(UserCreationForm):
    email = forms.EmailField(required=True, label='Email')
    username = forms.CharField(required=True, max_length=15, label='Логин',  min_length=2)
    password1 = forms.CharField(required=True, max_length=30, label='Пароль', min_length=8)
    password2 = forms.CharField(required=True, max_length=30, label='Повторите пароль')
    firstname = forms.CharField(required=True, max_length=25, label='Номер телефона', )

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

    def clean_username(self):
        username = self.cleaned_data.get("username")
        try:
            User._default_manager.get(username=username)
            # if the user exists, then let's raise an error message
            raise forms.ValidationError(
                self.error_messages['username_exists'],  # my error message
                code='username_exists',  # set the error message key
            )
        except User.DoesNotExist:
            return username  # if user does not exist so we can continue the registration process

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        user.first_name = self.cleaned_data['firstname']
        user.password1 = self.cleaned_data['password1']
        user.password2 = self.cleaned_data['password2']
        user.is_active = False

        if commit:
            user.save()
        return user
→ Ссылка