Django: How to set sessionid cookie for AnonymousUser without using SESSION_SAVE_EVERY_REQUEST

anonymous-users, django, session, session-cookies

Solution

Even explicitly modifying the session can fail (eg assigning an attribute to a session attribute).

You need to explicitly set `session.modified` to true

if hasattr(request, 'session') and not request.session.session_key:
    request.session.save()
    request.session.modified = True

Have a look at what the docs say on when sessions are saved.

Problem

I am attempting to track AnonymousUsers to figure out when they first come to the site, and when they then register to the website. To do so, I created a middleware with the relevant functionality, but this initially assumed that each AnonymousUsers already had a session associated with it (i.e. sessionid cookie will be set in first response & associated session is already created in django_session). Note: session app & middleware are present It seems that this is not the case, as looking at the session middleware, when an AnonymousUser first comes on the site, the session is never modified (Users do, since '_auth_user_id' and '_auth_user_backend' are set), and so is never created: SessionMiddleware.process_response ``` def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie. """ try: accessed = request.session.accessed modified = request.session.modified except AttributeError: pass else: if accessed: patch_vary_headers(response, ('Cookie',)) if modified or settings.SESSION_SAVE_EVERY_REQUEST: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) # Save the session data and refresh the client cookie. request.session.save() response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None) return response ``` Attempt 1 To try and overcome this, in my Middleware, which is placed below the Session Middleware, I would force a save() on the session to create it: ``` if hasattr(request, 'session') and not request.session.session_key: request.session.save() ``` This would provide the session_key, but unfortunately when SessionMiddleware.process_response is called, request.session.modified is still equal to False, and so the sessionid cookie is not set... Attempt 2 One way to do this seems to modify the session, in an arbitrary way, to ensure that `request.session.modified == True`, in the SessionMiddleware.process_response: ``` if hasattr(request, 'session') and not request.session.session_key: request.session.save() request.session['some_variable'] = True ``` This seems to fix my problem, without resorting to `SESSION_SAVE_EVERY_REQUEST`, which would be an overkill, but yet it does not seem quite right.... Question How to make sure the session is created for an AnonymousUser with no previous visit, without explicitly modifying the session, or having `SESSION_SAVE_EVERY_REQUEST=True`? Thanks for your help!

Original source