Django:如何将首个登录用户重定向至加载页面
Alright, let's tackle this redirect issue you're facing. The core problem here is that returning a response from the user_logged_in signal receiver doesn't work—Django ignores the return value of signal handlers because they're designed to handle side effects, not modify the response flow.
Let's walk through a couple of solid solutions to fix this:
1. Override the Login View (Recommended Approach)
Instead of relying on signals, handle the first-login logic directly in the login view. This gives you full control over the response after a successful login.
First, create a custom login view that inherits from Django's built-in LoginView:
from django.contrib.auth.views import LoginView from django.shortcuts import redirect from .utils import get_current_users, azure_auth_capacity, resume_pbi_capacity class CustomLoginView(LoginView): def form_valid(self, form): # Check logged-in user count BEFORE completing the login process existing_users_count = get_current_users().count() # Let Django handle the standard login flow (creates session, etc.) response = super().form_valid(form) # Trigger server startup and redirect if this is the first user if existing_users_count == 0: headers = azure_auth_capacity() resume_pbi_capacity(headers) return redirect('loading') # Proceed with default redirect for subsequent users return response
Update your urls.py to use this custom view instead of the default login route:
from django.contrib.auth import views as auth_views from .views import CustomLoginView urlpatterns = [ # Replace default login path with our custom view path('login/', CustomLoginView.as_view(), name='login'), # Other existing paths... path('', pbi_dashboard_list, name='home'), path('loading/', your_loading_view, name='loading'), ]
2. Use Session Flag + Post-Login Redirect Check
If you prefer keeping the signal, set a session flag in the receiver, then check that flag in your home view to trigger the redirect.
First, update your signal receiver:
from django.contrib.auth.signals import user_logged_in from django.dispatch import receiver from .utils import get_current_users, azure_auth_capacity, resume_pbi_capacity @receiver(user_logged_in) def sig_user_logged_in(sender, user, request, **kwargs): # Exclude current user to check if they're the first to log in existing_users = get_current_users().exclude(id=user.id) if existing_users.count() == 0: headers_capacity = azure_auth_capacity() resume_pbi_capacity(headers_capacity) # Set session flag to trigger post-login redirect request.session['redirect_to_loading'] = True
Modify your home view to check for this flag:
from django.shortcuts import redirect from django.contrib.auth.decorators import login_required @login_required def pbi_dashboard_list(request): # Check and clear the redirect flag from session if request.session.pop('redirect_to_loading', False): return redirect('loading') # Your existing dashboard logic here... return redirect('dashboard', dashboard_id)
3. Implement Loading Page with Polling
Don't forget to set up the loading page to wait for the PBI server to be ready. Use JavaScript to poll an API endpoint that checks the server status:
First, create a view to check PBI capacity status:
from django.http import JsonResponse from django.views.decorators.http import require_GET from .utils import azure_auth_capacity, get_pbi_capacity_status @require_GET def check_pbi_status(request): headers = azure_auth_capacity() status = get_pbi_capacity_status(headers) # Adjust condition based on Azure's readiness response return JsonResponse({'ready': status == 'Running'})
Add the URL for this endpoint:
path('check-pbi-status/', check_pbi_status, name='check_pbi_status'),
Then your loading.html template:
<!DOCTYPE html> <html> <head> <title>Starting PowerBI Server...</title> </head> <body> <h1>Loading, please wait...</h1> <p>The PowerBI server is starting up (this takes ~30 seconds).</p> <script> function checkServerReady() { fetch('/check-pbi-status/') .then(response => response.json()) .then(data => { if (data.ready) { window.location.href = '/'; } else { setTimeout(checkServerReady, 2000); } }) .catch(error => { console.error('Error checking server status:', error); setTimeout(checkServerReady, 2000); }); } window.onload = checkServerReady; </script> </body> </html>
Quick Fix for get_current_users()
Make sure your session counting function skips invalid/corrupted sessions:
def get_current_users(): active_sessions = Session.objects.filter(expire_date__gte=timezone.now()) user_id_list = [] for session in active_sessions: try: data = session.get_decoded() user_id = data.get('_auth_user_id') if user_id: user_id_list.append(user_id) except: # Skip invalid sessions to avoid counting errors continue return User.objects.filter(id__in=user_id_list)
The first approach is the cleanest—it keeps all login-related logic in one place and avoids the limitations of Django signals.
内容的提问来源于stack exchange,提问作者lese

