Request.method == POST equaling true in next function causing it to run prematurely

so i am running this code

def login_or_join(request):

    if request.method == "POST":
        option = request.POST.get("option")
        print('post request recieved')

        if option == "1":
            return login_screen(request)

        if option == '2':
            return in_game(request)

    return render(request,"login_or_join.html")

and def login_screen() looks like this

def login_screen(request):
    if request.method == "POST":
    
        username = request.POST.get("username")
        password = request.POST.get("password")
        print(username)
        print(password)

        user = authenticate(request, username=username, password=password)
    
        print(user)

        if user is not None:
            return redirect('join_lobby')
        else:
            return render(request,'login_page.html',)
    
    return render(request, 'login_page.html')

Whenever I click "option 1" it runs login_screen but in a way I don't want it to. it seems to just follow that request.method == "POST" and prints username and password immediately, meaning it is setting username and password immediately making any log in attempt wrong. But I don't want it to set those (or print them) until I've pressed the button on the next page. Further more when I hit "enter" or "log in" it doesn't reshow the page with the error message, it just goes back login_or_join(). I feel like I am taking crazy pills as I've been working on this website for a while and this is the first time I'm having this kind of issue. I've tried messing with it but feel I've been staring at it too long. Any help would be appreciated!

I guess the problem is that you are calling login_screen with request as parameter. But that variable is the parameter received on login_or_join so is the POST request with the option, neither a GET nor a POST with the username and password.

I think in this case you can just name the url and do:

if option == "1":
    return redirect(login_screen_name)
if option == "2":
    return redirect(in_game_screen_name)

You don't want to let the login screen process the request, but make a new, GET request, to the login_screen, so:

def login_or_join(request):
    if request.method == 'POST':
        option = request.POST.get('option')
        if option == '1':
            return redirect('name-of-login-screen')
        if option == '2':
            return redirect('name-of-in-game-view')
    return render(request, 'login_or_join.html')

where you pass the names of the views defined in the urls.py:

urlpatterns = [
    path('some/path/', login_screen, name='name-of-login-screen'),
    path('some/other/path/', in_game, name='name-of-in-game-view'),
]

This is the so-called Post/Redirect/Get architectural pattern [wiki]. This is also necessary to prevent unexpected behavior when you refresh in the browser. If the request that rendered the response was a POST request, hitting refresh in the browser will make a new POST request, so that means that if the request would for example add an item to a shopping basket, now you have added it twice.

Back to Top