'Django Redirect If Authenticated Mixin
i want to create a mixin to be redirect user to a specified page if they're already authenticated. i want to be able to use this mixin in different parts of the application without having to rewrite the logic over and over again.
i get a accounts.views.view didn't return an HttpResponse object. It returned None instead. error if the user is not authenticated but it works if user is authenticated. accounts is the app_name
here's my code in mixin.py
class RedirectIfAuthenticatedMixin:
"""
RedirectIfAuthenticatedMixin: redirect authenticated user to different page via redirect_to parameter
"""
redirect_to = None
def get(self, request):
"""
Get request handler to check if user is already authenticated
then redirect user to specified url with redirect_to
"""
if request.user.is_authenticated:
return HttpResponseRedirect(self.get_redirect_url())
# return ??? <- WHAT TO WRITE HERE TO ALLOW REQUEST TO CONTINUE EXECUTION
def get_redirect_url(self):
"""
Get the specified redirect_to url
"""
if not self.redirect_to:
raise ImproperlyConfigured('no url to redirect to. please specify a redirect url')
return str(self.redirect_to)
it works when i add this to the view itself
class RegisterView(RedirectIfAuthenticatedMixin, FormView):
"""
RegisterView: form view to handle user registration
"""
template_name = 'registration/register.html'
success_url = reverse_lazy('accounts:activation-sent')
form_class = RegistrationForm
def form_valid(self, form):
"""
Method to handle form submission and validation
"""
# save user information
user = form.save(commit = False)
user.email = form.cleaned_data['email']
user.set_password(form.cleaned_data['password'])
user.is_active = False
user.save()
# email configuration/compose to send to user
current_site = get_current_site(self.request)
subject = 'Activate Your Padumba Account'
message = render_to_string('registration/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
# send the account confirmation email to the user
user.email_user(subject = subject, message = message)
# send a flash message to the user
messages.success(self.request, ('Check Your Email For Account Activation Link'))
return super().form_valid(form)
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse_lazy('accounts:index'))
return super(RegisterView, self).get(request, *args, **kwargs)
Solution 1:[1]
The logic will not be evaluated if there is an override of the get method for that view. You probably better override the dispatch method. This will also prevent making POST, PUT, PATCH, DELETE, etc. requests to the view:
class RedirectIfAuthenticatedMixin:
redirect_to = None
def get_redirect_url(self):
if not self.redirect_to:
raise ImproperlyConfigured('no url to redirect to. please specify a redirect url')
return str(self.redirect_to)
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(self.get_redirect_url())
return super().dispatch(request, *args, **kwargs)
But you can actually make this a special case of the UserPassesTestMixin mixin [Django-doc]:
from django.contrib.auth.mixins import UserPassesTestMixin
class RedirectIfAuthenticatedMixin(UserPassesTestMixin):
redirect_to = None
def get_redirect_url(self):
if not self.redirect_to:
raise ImproperlyConfigured('no url to redirect to. please specify a redirect url')
return str(self.redirect_to)
def handle_no_permission(self):
return HttpResponseRedirect(self.get_redirect_url())
def test_func(self):
return not self.request.user.is_authenticated
Solution 2:[2]
@coder-six
I think implementation of such class will require you handle the main request
in implementing class i.e. implement also get method in the child class and
then from there call the get method of the of your mixin class. To make things easier you can change the RedirectIfAuthenticatedMixin get method to redirect_if_authenticated.
You will have to then call this method in every child class where you want this functionality. Example:
class RedirectIfAuthenticatedMixin:
"""
RedirectIfAuthenticatedMixin: redirect authenticated user to different page via redirect_to parameter
"""
redirect_to = None
def redirect_if_authenticated(self, request):
"""
Get request handler to check if user is already authenticated
then redirect user to specified url with redirect_to
"""
if request.user.is_authenticated:
return HttpResponseRedirect(self.get_redirect_url())
#other methods of class here ....
class RegisterView(FormView, RedirectIfAuthenticatedMixin):
"""
RegisterView: form view to handle user registration
"""
def form_valid(self, form):
"""
Method to handle form submission and validation
"""
pass
# THIS WORKS,...
def get(self, request, *args, **kwargs):
self.redirect_if_authenticated(request)
return #continue your request here if not authenticated
But I also think using a decorator might make things eaisier for you.
Decorator:
def redirect_on_authenticated(func):
def wrapper(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(self.get_redirect_url())
else:
return func(self, request, *args, **kwargs)
return wrapper
class RegisterView(FormView, RedirectIfAuthenticatedMixin):
"""
RegisterView: form view to handle user registration
"""
def form_valid(self, form):
"""
Method to handle form submission and validation
"""
pass
@redirect_on_authenticated
def get(self, request, *args, **kwargs):
self.redirect_if_authenticated(request)
return #continue your request here if not authenticated
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
