Email verification in django python

I try to make email verification in django, everyting works correctly, but if user creates account with someone other's email and if user will not confirm email, owner of this email will not be able to register because account is alredy registered and is_active is False. Here my views.py with reg form '''

from django.shortcuts import render, redirect
from django.http.request import HttpRequest
from django.http import JsonResponse
from .forms import UserRegisterForm, UserLoginForm
from .models import User
from .tokens import accound_activate_token

from django.contrib.sites.shortcuts import get_current_site
from django.template.loader import render_to_string
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.encoding import force_bytes, force_str

from django.core.mail import send_mail

# from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import authenticate, login, logout

def send_email_validation(request: HttpRequest, user: User, form: UserRegisterForm):
    current_site = get_current_site(request)
    mail_subject = "Activate your account"
    message = render_to_string(
        "users/emails/email_activation.html",
        {
            "user": user,
            "domain": current_site.domain,
            "uid": urlsafe_base64_encode(force_bytes(user.pk)),
            'token': accound_activate_token.make_token(user)
            
        }
    )
    from_email = "xxx"
    to_email = form.cleaned_data["email"]
    send_mail(
        mail_subject, message, from_email,
        [to_email]
    )

def register_page(request: HttpRequest):
    if request.method == "GET":
        reg_form = UserRegisterForm()

    if request.method == "POST":
        reg_form = UserRegisterForm(request.POST)
        # create user and redirect to login
        if reg_form.is_valid():
            user: User = reg_form.save(commit=False)
            user.is_active = False
            user.save()

            # sending email for validation
            send_email_validation(request, user, reg_form)

            return redirect("users_login")
    context = {
        "form": reg_form
    }
    
    return render(request, "users/register.html", context)

def activate_email(reqest: HttpRequest, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)

    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None

    if user and accound_activate_token.check_token(user, token):
        user.is_active = True
        user.save()
    return redirect("main_page")

'''

tokens.py '''

from django.contrib.auth.tokens import PasswordResetTokenGenerator

class AccoundActivationTokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return f"{user.pk}{timestamp}{user.is_active}"
    
accound_activate_token = AccoundActivationTokenGenerator()

'''

I think I need to save user only after email verified successfully, but I don't know if it will be correct

Based on the described scenario, one effective approach is to add a created_at field to the User model to track account creation time. Upon user registration, a verification email should be sent, and the account should remain inactive until the email is verified. If the user does not verify their email within a defined time window (e.g., 1 hour), the unverified account can be automatically deleted. This allows the same email address to be used again for registration after the expiration period, ensuring legitimate users are not blocked by inactive, unverified accounts.

I think I got it, I just need to check user while registration and delete it if account is not active

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField(
        label=_("Email"),
        max_length=100,
        required=True,
    )
    first_name = forms.CharField(
        label=_("First Name"),
        max_length=100,
        required=True,
    )
    last_name = forms.CharField(
        label=_("Last Name"),
        max_length=100,
        required=True,
    )

    def __init__(self, *args, **kwargs):
        super(UserRegisterForm, self).__init__(*args, **kwargs)
        # clear hepl texts 
        for field in self.fields.values():
            field.help_text = None

    def clean_email(self):
        email = self.cleaned_data['email']
        try:
            # get and delete user with not active account
            user = User.objects.get(email=email)
            if not user.is_active:
                user.delete()
                return email
            
            # user exists and acount is active
            raise forms.ValidationError(_("Email already exists")) 
        except User.DoesNotExist:            
            return email
        
    class Meta:
        model = User
        fields = [
            "email", 
            "first_name",
            "last_name",
            "password1", 
            "password2"
        ]
Вернуться на верх