I'm trying to build an email verification for user signup using CreateView
. This view check whether the user is a new or already existing inactive user? and resend verification if the user is inactive.
Here's how I did it(email sending part),
views.py
class SignUpView(CreateView):
""" SignUp view """
form_class = SignUpForm
success_url = reverse_lazy('login')
template_name = 'registration/register.html'
def send_activation_email(self, request, user):
""" sends email confirmation email """
uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
token = token_generator.make_token(user)
domain = get_current_site(request).domain
schema = request.is_secure() and "https" or "http"
link = reverse('user_activation', kwargs={'uidb64': uidb64, 'token': token})
url = '{}://{}{}'.format(schema, domain, link)
payload = {
'receiver': user.email,
'email_body': {
'username': user.username,
'email_body': 'Verify your email to finish signing up for RapidReady',
'link': url,
'link_text': 'Verify Your Email',
'email_reason': "You're receiving this email because you signed up in {}".format(domain),
'site_name': domain
},
'email_subject': 'Verify your Email',
}
Util.send_email(payload)
messages.success(request, 'Please Confirm your email to complete registration.')
def get(self, request, *args, **kwargs):
""" Prevents authenticated user accessing registration path """
if request.user.is_authenticated:
return redirect('home')
return super(SignUpView, self).get(request, *args, **kwargs)
def form_valid(self, form):
""" Handles valid form """
form = self.form_class(self.request.POST)
user = form.save(commit=False)
user.is_active = False
user.save()
self.send_activation_email(self.request, user)
return render(self.request, 'registration/confirm_email.html', {'email': user.email})
def post(self, request, *args, **kwargs):
""" Handles existing inactive user registration attempt """
form = self.form_class(self.request.POST)
if User.objects.filter(email=request.POST['email']).exists():
user = User.objects.get(email=request.POST['email'])
if not user.is_active:
self.send_activation_email(request, user)
return render(self.request, 'registration/confirm_email.html', {'email': user.email})
# if no record found pass to form_valid
return self.form_valid(form)
util.py
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return text_type(user.is_active) + text_type(user.pk) + text_type(timestamp)
token_generator = TokenGenerator()
class EmailThread(threading.Thread):
def __init__(self, email):
self.email = email
threading.Thread.__init__(self)
def run(self):
self.email.send()
class Util:
@staticmethod
def send_email(data):
msg_plain = render_to_string('email/email_normal_email.txt', data['email_body'])
msg_html = render_to_string('email/email_normal_email.html', data['email_body'])
msg = EmailMultiAlternatives(data['email_subject'], msg_plain, config('EMAIL_HOST_USER'), [data['receiver']])
msg.attach_alternative(msg_html, "text/html")
EmailThread(msg).start()
In the above code, I used form_valid()
method to handle a new user registration and the post()
method to check whether the user is new or already registered inactive user.
If no record found the post()
method will call form_valid()
method passing the form as an argument(last line in views). And this logic works just fine.
So, my main question is, 'Are there any negative effects due to this implementation?' and any advice(best practices, improvements, etc.) will be greatly appreciated.
1 Answer 1
You have a problem in the post()
method.
If the user does not exist you return self.form_valid(form)
, so if a new user in registration form gives a validation error. You will have an error because you called form_valid()
but form is not valid.
You can use return super().post(request, *args, **kwargs)
instead of return self.form_valid(form)
. Like this:
def post(self, request, *args, **kwargs):
""" Handles existing inactive user registration attempt """
form = self.form_class(self.request.POST)
if User.objects.filter(email=request.POST['email']).exists():
user = User.objects.get(email=request.POST['email'])
if not user.is_active:
self.send_activation_email(request, user)
return render(self.request, 'registration/confirm_email.html', {'email': user.email})
# if no record found pass to form_valid
return super().post(request, *args, **kwargs)
-
1\$\begingroup\$ I edited to improve the English spelling and grammar. But I don't know Django, so please check that my rewriting hasn't accidentally changed your meaning! \$\endgroup\$Toby Speight– Toby Speight2022年03月12日 11:32:41 +00:00Commented Mar 12, 2022 at 11:32