Zatigem
Zatigem

Reputation: 335

Set variable to an expired session out of a view in Django

I’m trying to set a variable to an expired session out of a view in Django.

I’m aware of django’s documentation on Using sessions out of views. But in my case, I try to set a session variable in a custom management command.

Here’s what I tried :

from django.contrib.sessions.models import Session

class Command(BaseCommand):
    help = "My custom command."

    def handle(self, *args, **options):
        for s in Session.objects.all():
            s['my_variable'] = None

What I get is this error:

TypeError: 'Session' object does not support item assignment

I also tried:

[…]
ss = SessionStore(session_key=s.session_key)
ss['my_variable'] = None
ss.save()

This creates another session but does not modify the existing one…

How can I set my_variable to None ?

Edit: The session I’m trying to set a variable to is expired

Upvotes: 0

Views: 143

Answers (2)

Zatigem
Zatigem

Reputation: 335

You can’t do that on expired sessions. Django does not allow you.

But here is a hack:

class Command(BaseCommand):
    help = "My custom command."

    def handle(self, *args, **options):
        future = datetime.datetime(datetime.MAXYEAR, 1, 1)
        for s in Session.objects.all():
            ed = s.expire_date
            s.expire_date = future
            s.save()
            ss = SessionStore(session_key=s.session_key)
            ss['my_variable'] = None
            ss.save()
            updated_session = Session.objects.get(session_key=s.session_key)
            updated_session.expire_date = ed
            updated_session.save()

Upvotes: 1

Anentropic
Anentropic

Reputation: 33833

Try this:

from django.contrib.sessions.models import Session

class Command(BaseCommand):
    help = "My custom command."

    def handle(self, *args, **options):
        store_cls = Session.get_session_store_class()
        for session in Session.objects.all():
            s = store_cls(session.session_key)
            s['my_variable'] = None
            # so that any subsequent code which reads from the session sees your change
            s.save()

The code is loading saved session data from the db, but as Session model instances.

These are not the same as the session objects you get back from the SessionStore in the code shown at https://docs.djangoproject.com/en/4.2/topics/http/sessions/#using-sessions-out-of-views

We actually don't really want to deal with Session model instances at all, what we need is the session_key from the instance, so that we can instantiate the session store.

We can then update the value in session object via __setitem__ and save it back into the db https://github.com/django/django/blob/main/django/contrib/sessions/backends/db.py#L73 (until we do that our change won't be visible to any other code that tries to read the session data).

Since we only need the session_key we can amend the code above:

from django.contrib.sessions.models import Session

class Command(BaseCommand):
    help = "My custom command."

    def handle(self, *args, **options):
        store_cls = Session.get_session_store_class()
        for session_key in Session.objects.values_list("session_key", flat=True):
            s = store_cls(session_key)
            s['my_variable'] = None
            # so that any subsequent code which reads from the session sees your change
            s.save()

Upvotes: 0

Related Questions