Search code examples
pythondjangodjango-viewsdjango-authentication

Django: How to add next to manual login redirect?


I have a view:

def create_something(request):
    ...

I want to redirect to login if a person isn't logged in. Normally I'd use:

@login_required
def create_something(request):
    ...

but 🍑... I want to add a message before the redirect.

I wanted to do it like this:

def create_something(request):
    if not request.user.is_authenticated:
        messages.info(request, 'You must be logged in to create a thing 👀.')
        return redirect('login')
    ...

However, that doesn't include a ?next in the url to go back to the page I was going to.

So my question is:

How would you manually redirect back to the login page WITH a manually added ?next query?


Solution

  • We can look at the source code [GitHub] of the @user_passes_test decorator [Django-doc] and determine how such redirect is done.

    In the source code we see:

    # ⋮
    path = request.get_full_path()
    from django.contrib.auth.views import redirect_to_login
    return redirect_to_login(path, resolved_login_url, redirect_field_name)

    We can thus mimic this behaviour with:

    from django.contrib.auth import REDIRECT_FIELD_NAME
    from django.contrib.auth.views import redirect_to_login
    from django.urls import reverse
    
    def create_something(request):
        if not request.user.is_authenticated:
            messages.info(request, 'You must be logged in to create a thing �.')
            path = request.get_full_path()
            return redirect_to_login(path, reverse('login'))
        # …

    Here the .redirect_to_login(…) function [Django-doc] will thus produce a redirect where the querystring will contain a key next=… where next is associated with the path.

    You should use path = request.build_absolute_uri() in case the schema or hostname.