Reputation: 3076
I have a login form in django, where I need to do some extra checks in my clean method:
class LoginForm(BootstrapFormMixin, forms.Form):
email = forms.EmailField(required=True, max_length=30)
password = forms.CharField(required=True, widget=forms.PasswordInput)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = self.__class__.__name__.lower()
self.helper.form_action = ''
self.helper.layout = Layout(
Field('email'),
Field('password'),
Div(
Submit('submit', _('Login'),
css_class="btn btn-block btn-success"),
css_class=''
)
)
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
user = authenticate(email=email, password=password)
if user:
company = user.company
if not company.is_active:
# here I want to make a redirect; if is it possible to add a flash message it would be perfect!
raise forms.ValidationError(_('Account activation is not finished yet'))
else:
raise forms.ValidationError(_('Invalid credentials'))
return self.cleaned_data
It works properly, but when credentials are correct, but user's related object named company is not active (is_active=False) I want to redirect user to another view and add some flash message (using django.contrib.messages
maybe).
Is it possible to do such redirection?
Thank you!
Upvotes: 0
Views: 2007
Reputation: 334
So I am going to risk a guess that you still want to log the user in FIRST before redirecting the user.
If the above is true, accomplish the PRIMARY functionality of the form first.
The redirect can run in "views" where the user login function needs to run first BEFORE you can redirect the user. Prior to this point there is no need to run additional verification.
Here is how I would write the snippet for the view - only to show the redirect related steps (not the whole view). Assume 'home:index' routes the user to the normal redirect page after login and 'company:add_company_info' routes the user to the aberrant page with the message.
if form.is_valid():
user = form.login(request) # assume this form function calls django authenticate and will return the user if successful
if user:
login(request, user)
if user.company.is_active: # this is assuming the user.company relationship exists
return redirect('home:index')
else:
messages.add_message(request, messages.INFO, "Please fill in your company information")
return redirect('company:add_company_info')
Upvotes: 0
Reputation: 309029
You could specify a particular error code when you raise the validation error in your form.
def clean(self):
...
if not company.is_active:
# here I want to make a redirect; if is it possible to add a flash message it would be perfect!
raise forms.ValidationError(_('Account activation is not finished yet'), code='inactive')
Then, in the view, you can check the error codes, and redirect if appropriate. You can check the error codes using form.errors.as_data()
. Since you raise the ValidationError
in the clean
method, the error doesn't belong to a particular field so you can access it using the __all__
key.
if form.is_valid():
# login user then redirect
else:
for error in form.errors.as_data()['__all__']:
if error.code == 'inactive':
messages.warning(request, 'Account is inactive')
return redirect('/other-url/')
# handle other errors as normal
Upvotes: 0
Reputation: 34593
You could just add a boolean redirect
attribute to the form to know when to do the redirect:
class LoginForm(BootstrapFormMixin, forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.redirect = false
. . .
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
user = authenticate(email=email, password=password)
if user:
company = user.company
if not company.is_active:
self.redirect = True
raise forms.ValidationError()
else:
raise forms.ValidationError(_('Invalid credentials'))
return self.cleaned_data
from django.contrib import messages
from django.shortcuts import redirect
def your_view(request):
form = LoginForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
# whatever
else:
if form.redirect:
messages.add_message(request, messages.ERROR,
_('Account activation is not finished yet'))
return redirect('wherever')
return render(request, 'your-template.html', {'form': form})
Upvotes: 2