[Python] Most optimized way to delete all sessions for a specific user in Django?

Discussão em 'Python' iniciado por Stack, Março 7, 2025.

  1. Stack

    Stack Membro Participativo

    I'm running Django 1.3, using Sessions Middleware and Auth Middleware:

    # settings.py

    SESSION_ENGINE = django.contrib.sessions.backends.db # Persist sessions to DB
    SESSION_COOKIE_AGE = 1209600 # Cookies last 2 weeks


    Each time a user logs in from a different location (different computer/browser), a new Session() is created and saved with a unique session_id. This can result in multiple database entries for the same user. Their login persists on that node until the cookie is deleted or session expires.

    When a user changes their password, I want to delete all unexpired sessions for that user from the DB. That way after a password change, they're forced to re-login. This is for security purposes, such as if your computer got stolen, or you accidentally left yourself logged-in on a public terminal.

    I want to know the best way to optimize this. Here's how I've done it:

    # sessions_helpers.py

    from django.contrib.sessions.models import Session
    import datetime

    def all_unexpired_sessions_for_user(user):
    user_sessions = []
    all_sessions = Session.objects.filter(expire_date__gte=datetime.datetime.now())
    for session in all_sessions:
    session_data = session.get_decoded()
    if user.pk == session_data.get('_auth_user_id'):
    user_sessions.append(session)
    return user_sessions

    def delete_all_unexpired_sessions_for_user(user, session_to_omit=None):
    for session in all_unexpired_sessions_for_user(user):
    if session is not session_to_omit:
    session.delete()


    A very simplified view:

    # views.py

    from django.http import HttpResponse
    from django.shortcuts import render_to_response
    from myapp.forms import ChangePasswordForm
    from sessions_helpers import delete_all_unexpired_sessions_for_user

    @never_cache
    @login_required
    def change_password(request):
    user = request.user

    if request.method == 'POST':
    form = ChangePasswordForm(data=request)

    if form.is_valid():
    user.set_password(form.get('password'))
    user.save()
    request.session.cycle_key() # Flushes and replaces old key. Prevents replay attacks.
    delete_all_unexpired_sessions_for_user(user=user, session_to_omit=request.session)
    return HttpResponse('Success!')

    else:
    form = ChangePasswordForm()

    return render_to_response('change_password.html', {'form':form}, context_instance=RequestContext(request))


    As you can see in sessions_helpers.py, I have to pull every unexpired session out of the DB, Session.objects.filter(expire_date__gte=datetime.datetime.now()), decode all of them, and then check to see if it matches a user or not. This will be extremely costly to the database if there are, say, 100,000+ sessions stored in there.

    Is there a more-database-friendly way to do this? Is there a Sessions/Auth Middleware setting that'll let you store the username as a column in the Sessions table so I can run SQL against that, or will I have to modify Sessions to do that? Out-of-the-box it only has session_key, session_data, and expire_date columns.

    Thanks for any insight or help you can offer. :)

    Continue reading...

Compartilhe esta Página