'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