Is there a way for me to stop the other validations after the first redirect
in views.py
from django.contrib import messages
# from django.core.exceptions import ValidationError
from django.shortcuts import render, redirect
def register(request):
if request.method == 'POST':
form = request.POST
phone_number = validate_phone(request, form.get("phone_number"))
username = validate_user_name(request, form.get("username"))
password = validate_password(request, password1=form.get("password1"),password2=form.get("password2"))
....other_fields....
return render(request, 'registration.html',)
def validate_user_name(request, username):
username = username.strip()
new = MyUser.objects.filter(username=username)
if new.count():
messages.error(request, "User with that Username Already Exist")
return redirect("pre_register")
# raise ValidationError("User with that Username Already Exist", code="username_error")
return username
def validate_password(request, password1, password2):
if password1 and password2 and password1 != password2:
messages.error(request, "Passwords don't match")
return redirect("pre_register")
# raise ValidationError("Password don't match")
return password2
....other_validations....
in registration.html:
<h3 >Apply as a Member</h3>
{% for message in messages %}
<li{% if message.tags %} {% endif %}>{{ message.tags }} : {{message}}</li>
{% endfor %}
<form method="post">
<input type="text" placeholder="Username *" value=""
required="required" name="username"/>
<input type="text" minlength="10" maxlength="10" name="phone_number"
placeholder="Your Phone *" value="" required="required"/>
<input type="password" placeholder="Password *" value=""
required="required" , name="password1"/>
<input type="password" placeholder="Confirm Password *"
value="" required="required" , name="password2"/>
</form>
Let's say a user enters a username that already exists, what I want is:
- To keep the already entered post data
- Once it hits this line
messages.error(request, "User with that Username Already Exist")
return redirect("pre_register")
, I want just this as result(In template)
error: User with that Email ALready Exists
Instead, I get all the error messages at once
error: User with that Email ALready Exists
error: Passwords don't match
...all the other errors....
I know it's because technically, this is what I should get but how do I achieve what I want above. I think a way to do this would be to clear all the messages before I set the error messages but that would mean giving the server more work to do as it would still go through all of them before leaving just the last one (And the fact that I don't know how to even do it )
Any help on this would be appreciated immensely
CodePudding user response:
First of all, I think you're confusing when to use render and when to use redirect. The usual pattern is to use redirect
when your form validates so the user can't accidentally resubmit data, and to use render
when the data is invalid so the errors get rendered. You're doing the opposite. See this antipattern for more details.
Secondly, the issue is that your validation function returns an HTTP response. The user never gets redirected in your validation functions. You need to return the HTTP response from the view function for the user to get redirected. You could probably use the commented approach with raising ValidationErrors
and then catching them in the view. If the error occurs, you add a message and render the template.
Something like:
def register(request):
if request.method == 'POST':
form = request.POST
try:
phone_number = validate_phone(request, form.get("phone_number"))
username = validate_user_name(request, form.get("username"))
password = validate_password(request, password1=form.get("password1"),password2=form.get("password2"))
....other_fields....
# If all validations pass, you redirect
return redirect('pre_register')
except ValidationError as e:
messages.error(request, str(e))
# passes down to render
# This gets called when it's GET request or the form validation failed.
return render(request, 'registration.html',)