Search code examples
djangosessioncookiessession-cookies

Django, how to get the time until a cookie expires


Before marked as dup (I believe many answers are incorrect becase): According to my research:

  • request.session.get_expiry_age returns the TOTAL lifespan of the cookie, not the time from now until it expires. It always returns the same value, irrespecitive of how much time is left.
  • Similarly get_expiry_date adds the total lifespan to the now time. It always increases when called. Hence niether of them help.

settings.SESSION_SAVE_EVERY_REQUEST refreshes the cookie on every request, this is NOT what I am trying to achieve.

get_session_cookie_age() ONLY returns the value of settings.SESSION_COOKIE_AGE, as seen in the sourcecode:

def get_session_cookie_age(self):
    return settings.SESSION_COOKIE_AGE

I use the cached_db session back end. The cached part is made none in void because it has to save the cookie everytime, hence SESSION_SAVE_EVERY_REQUEST is not applicable. The reason I ask this question is because I wish to refresh a cookie ONLY if the time left has gone below a threshold, and hence have some hysterious (have the benefits of caching and auto refreshing).

Here is my code that does not work because of the behaviour of get_expiry_age/get_expiry_date as explained above:

from django.conf import settings
from django.utils.deprecation import MiddlewareMixin

class SessionExpiry(MiddlewareMixin):
    def process_request(self, request):
        """Automatically refresh a session expirary at a certain limit.

        If request.session age goes below settings.SESSION_REFRESH, then
        set the sessions expirary age to settings.SESSION_COOKIE_AGE. The
        session is not refreshed every time to have the caching benefits of
        the cached_db backend.
        """
        try:
            empty = request.session.is_empty()
        except AttributeError:
            return None
        if (empty or not getattr(settings, 'SESSION_REFRESH', None)):
            return None
        if request.session.get_expiry_age() < settings.SESSION_REFRESH:
            request.session.set_expiry(settings.SESSION_COOKIE_AGE)
        return None

Solution

  • This is an area of Django that's confusing, in both design and documentation. The easiest way to figure out what's going on is to look at the source code.

    To get what you want you need to set a custom expiration as a datetime. If you use seconds (including the default SESSION_COOKIE_AGE) that is interpreted as the number of seconds from now; that is, from whenever you ask.

    So to set the expiration, use:

    # Using timedelta will cause the session to save the expiration time as a datetime.
    request.session.set_expiry(timedelta(seconds=settings.SESSION_COOKIE_AGE))
    

    If you do that, calls to get_expiry_age() will return the actual difference between the current datetime and the datetime set as the expiry.

    Be sure to note the warning in the set_expiry() documentation: "Note that datetime and timedelta values are only serializable if you are using the PickleSerializer."