1

I want to secure each webpage of my django app, and what I want is that after login the user should be redirected to the previous page he was trying to access. So in accounts/views.py this is the login function I am using for that:

def login(request):
    if request.method == 'POST':
        #some code

        if user is not None:
            auth.login(request, user)
            return redirect(request.POST.get('next','dashboard'))
        else:
            #some code

    else:
        #some code

Now, I have used @login_required condition for each view of my webapp in this way:

@login_required(login_url='login')
def profile(request):
    return render(request, 'profile.html')

my login.html (reference):

<form method="POST" action="/accounts/auth">
    {% csrf_token %}
    <input type="hidden" name="next" value="{{ request.GET.next }}" />
    {{ login_form }}
    <input type="submit">
</form>

Now if the user visits accounts/profile without login, then he is redirected to accounts/login?next=/accounts/profile, so after login he is successfully redirected to accounts/profile as the value of 'next' is set to /accounts/profile and in login function if the user is authenticated then i have used return redirect(request.POST.get('next','dashboard')) which means redirect to the value of next if it is entered, otherwise /accounts/dashboard.

Now coming to my issue, if I try to access the login page directly (i.e. /accounts/login) then as there is no next variable in the URL, so according to my login function I should be redirected to /accounts/dashboard but instead, I am getting the following error: Reverse for '' not found. '' is not a valid view function or pattern name. what am I doing wrong?

Extra note: I have even tried adding LOGIN_REDIRECT_URL='dashboard' to my settings.py but still when the next variable is blank I am not redirected to the dashboard

Mostly the mistake is in this piece of code: redirect(request.POST.get('next','dashboard'))

yogeshiitm
  • 179
  • 1
  • 17
  • `LOGIN_REDIRECT_URL` should be a URL path, so maybe `/dashboard`. See the docs here; https://docs.djangoproject.com/en/3.1/ref/settings/#login-redirect-url – markwalker_ Jan 14 '21 at 10:04
  • tried it, but I'm getting the same error `Reverse for '' not found. '' is not a valid view function or pattern name.` – yogeshiitm Jan 14 '21 at 10:24
  • 1
    Well that's a separate problem. That's something using the url resolvers without an argument to lookup. I'm guessing that's because `next` is being set as an empty string and then being used in the redirect – markwalker_ Jan 14 '21 at 10:30

2 Answers2

2

You should be more defensive in your code to check for a value before sending it as the redirect location.

So assuming that you have a URL path named dashboard based on your code;

path('accounts/dashboard/', Dashboard.as_view(), name='dashboard'),
from django.urls import reverse


def login(request):
    if request.method == 'POST':
        ...
        if user is not None:
            auth.login(request, user)
            next_param = request.POST.get('next')
            if next_param:
                url = next_param
            else:
                url = reverse('dashboard')

            return redirect(url)

markwalker_
  • 12,078
  • 7
  • 62
  • 99
  • this has a little problem, lets say i want to visit `accounts/profile` then the login url will be `accounts/login?next=/accounts/profile` and so after login i will be redirected to `accounts/dashboard?next=/accounts/profile`. – yogeshiitm Jan 14 '21 at 10:58
  • Yes, good point. My mistake. I've edited in the case there is a `next` value. You might want to consider how that value is added to the form to ensure that it's a valid URL to redirect to. – markwalker_ Jan 14 '21 at 11:01
0

Finally figured out my mistake. Looking at the error Reverse for "" not found. "" is not a valid view function or pattern name., it seems that the piece of code: return redirect(request.POST.get('next','dashboard')) is trying to redirect to "".

Which means that when I am accessing accounts/login, the next variable is not None (because by default next is being set as an empty string and then being used in the redirect) so request.POST.get('next') = "" and thus it's unable to redirect to'dashboard'. I modified my login function as follows:

def login(request):
    if request.method == 'POST':
        #some code

        if user is not None:
            auth.login(request, user)

            #new code
            if request.POST.get('next') != '':
                return redirect(request.POST.get('next'))
            else:
                return redirect('dashboard')

        else:
            #some code

    else:
        #some code

Extra observation: If request.POST.get('next') == "/" then the page is redirected to http://127.0.0.1:8000/ but if request.POST.get('next') == "" then it gives an error Reverse for "" not found. because "" is not a valid view function or URL pattern name.

yogeshiitm
  • 179
  • 1
  • 17