Django登录失败重渲染页面URL保留视图名问题求助
Hey there! I get your frustration—you want a clean, user-friendly URL for your login page, but you're stuck between showing error messages (which requires rendering the template directly) and keeping the URL nice (which makes redirecting tricky). Let's walk through two solid solutions to fix this.
Solution 1: Handle Both GET/POST in the Same View (No Redirect Needed)
The simplest fix is to structure your view to handle both the initial form load (GET request) and form submission (POST request) while using a clean URL. Here's how:
Step 1: Update Your URL Pattern
First, change your URL path to something more semantic (like /login instead of /login_user):
# urls.py path('login', views.login_user, name='login_user')
Step 2: Refactor Your View
Modify your view to check the request method. For GET requests, render the empty login form. For POST requests, validate credentials—if they fail, re-render the form with your error message. This keeps the URL as /login the whole time:
# views.py from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect def login_user(request): if request.method == 'POST': # Grab form data email = request.POST.get('email') password = request.POST.get('password') # Authenticate the user user = authenticate(request, username=email, password=password) if user is not None: # Login successful, redirect to your desired page login(request, user) return redirect('home') # Replace with your home page name else: # Login failed, re-render the form with error return render(request, 'sign_in/sign-in.html', { 'login_error': "We couldn't find an account with that email and/or password." }) # GET request: render empty login form return render(request, 'sign_in/sign-in.html')
Step 3: Keep Your Form Action the Same
Your existing form action is fine—since we updated the URL name to point to the clean /login path, it'll work perfectly:
<form class="sign_in" method="post" action="{% url 'sign-in:login_user' %}"> {% csrf_token %} <!-- Don't forget this! --> <!-- Your form fields here --> </form>
Solution 2: Use Django's Messages Framework (For Redirects)
If you prefer to redirect after a failed login (maybe to maintain a strict POST-redirect-GET pattern), Django's built-in messages framework lets you pass error messages across redirects. Here's how to set it up:
Step 1: Ensure Messages Framework is Enabled
First, confirm these are in your settings.py (they should be there by default if you used startproject):
# settings.py INSTALLED_APPS = [ ... 'django.contrib.messages', ... ] MIDDLEWARE = [ ... 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ... ] # Optional: Set a message storage backend (session is default) MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
Step 2: Update Your View to Use Messages
Instead of passing the error via render(), add an error message and redirect back to the login page:
# views.py from django.contrib import messages from django.contrib.auth import authenticate, login from django.shortcuts import redirect, render def login_user(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') user = authenticate(request, username=email, password=password) if user is not None: login(request, user) return redirect('home') else: # Add error message to session messages.error(request, "We couldn't find an account with that email and/or password.") # Redirect back to login page return redirect('sign-in:login_user') return render(request, 'sign_in/sign-in.html')
Step 3: Display Messages in Your Template
Add this snippet to your sign-in.html template to show the error message:
<!-- In sign-in.html --> {% if messages %} {% for message in messages %} <div class="alert alert-danger">{{ message }}</div> {% endfor %} {% endif %} <!-- Your login form below --> <form class="sign_in" method="post" action="{% url 'sign-in:login_user' %}"> {% csrf_token %} <!-- Form fields --> </form>
Final Notes
- URL Cleanup: Always use semantic URLs like
/loginor/sign-ininstead of view function names—this makes your site more user-friendly and maintainable. - CSRF Token: Don't forget to include
{% csrf_token %}in your form—it's required for Django to validate POST requests securely.
Either solution will fix your problem: Solution 1 is simpler for basic cases, while Solution 2 follows the POST-redirect-GET pattern which is good for avoiding duplicate form submissions.
内容的提问来源于stack exchange,提问作者tjkso

