Removing sessions from Redis (Django)

2020-06-23 09:28发布

问题:

I'm using Django and Redis as session engine (also Celery, but that is something else). It works perfectly and I can see an improvement in speed.

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

I have a script that runs every minute to check the active users through some methods and if the user hasn't been active in the latest minute, then the session gets removed. This is done for customer's tracking needs.

This script was working perfectly until I switched to Redis as a session engine. The session gets indeed removed from the DB but not from Redis. I'm not using any Django built-in method for this but my own function:

def clean_sessions():
    stored_sessions = Session.objects.all()
    active_users = active_users(minutes=1)
    active_users_ids = [user.id for user in active_users]
    for session in stored_sessions:
        session_uid = session.get_decoded().get('_auth_user_id')
        if not session_uid:
            session.delete()
            continue
        if session_uid not in active_users_ids:
            user = User.objects.get(pk=session_uid)
            ## some code between ##
            session.delete()

My question is, how do I remove the session from the cache as well, so the user is actually logged out?

回答1:

It wasn't very straightforward but I was able to fix it. I imported this from the file I have my clean_sessions():

from importlib import import_module
from django.conf import settings

Then, inside the function, I loaded the SessionStore object:

SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

From there, it was very easy to remove the sessions, leaving the method like this:

def clean_sessions():
    stored_sessions = Session.objects.all()
    active_users = Request.objects.active_users(seconds=15)
    active_users_ids = [user.id for user in active_users]
    for session in stored_sessions:
        SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
        s = SessionStore(session_key=session.session_key)
        session_uid = session.get_decoded().get('_auth_user_id')
        if not session_uid:
            s.delete()
            continue
        if session_uid not in active_users_ids:
            ## some code ##
            s.delete()

It's very important to load the right SessionStore from whatever session engine you're using, otherwise it will fail to remove it from both places (DB and cache).



回答2:

In case someone else needs this for clearing all session data (e.g during tests) depending on backend In this case Redis and The database:

from django.conf import settings
from django_redis import get_redis_connection
from django.contrib.sessions.models import Session

REDIS = "django.contrib.sessions.backends.cache"
DATABASE = "django.contrib.sessions.backends.db"
REDIS_AND_DATABASE = "django.contrib.sessions.backends.cached_db"


def clear_all_session_data_globally():
    """
    This will log out every user instantly and delete whatever they were working on, use with caution
    :return:
    """
    if settings.SESSION_ENGINE in [REDIS, REDIS_AND_DATABASE]:
        get_redis_connection("default").flushall()

    if settings.SESSION_ENGINE in [DATABASE, REDIS_AND_DATABASE]:
        Session.objects.all().delete()