Skip to content

Instantly share code, notes, and snippets.

@aleksihakli
Last active August 20, 2021 16:07
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aleksihakli/27ddd0bba822ae219f58c170db75281b to your computer and use it in GitHub Desktop.
Save aleksihakli/27ddd0bba822ae219f58c170db75281b to your computer and use it in GitHub Desktop.
Django single session
from django.conf import settings
from django.contrib.sessions.models import Session
from django.db import models
class UserSession(models.Model):
"""
UserSession
Session tracking and management inspired by Gavin Ballard:
http://gavinballard.com/associating-django-users-sessions/
Check the signals module for an implementation
that can be built on top of this data model.
When an user or his or her session data is deleted,
these objects are also deleted because of the default
cascading foreign key deletion policy.
"""
user = models.ForeignKey(settings.AUTH_USER_MODEL)
session = models.ForeignKey(Session)
from logging import getLogger
from django.conf import settings
from django.contrib.auth.signals import user_logged_in
from django.db import transaction
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import UserSession
log = getLogger(__name__)
def delete_sessions(user):
"""
Delete all user sessions we are tracking.
TODO: If login is _very_ slow profile this and see
into optimizing the deletion logic with
select_related and deleting the whole queryset
of sessions instead of looping through related objects.
"""
user_sessions = UserSession.objects.filter(user=user)
log.info('Deleting all %s sessions for user %s', user_sessions.count(), user)
for user_session in user_sessions:
user_session.session.delete()
def create_user_session(request, user):
"""
create_user_session
Create an intermediate object for tracking user sessions.
The Sessions API is very hard to use and this tracking logic
set up a clean-to-use API for managing authorized session states.
Inspired by Gavin Ballard, tweaked with codecraft's insight:
http://gavinballard.com/associating-django-users-sessions/
http://stackoverflow.com/a/5131421/7120972
"""
log.info('User %s logged in, setting up session tracking', user)
# Make sure the session user is creating is in the database
# See the Stackoverflow elaboration on this
if not request.session.exists(request.session.session_key):
request.session.create()
# Create a tracking object for the session
UserSession.objects.get_or_create(
user=user,
session_id=request.session.session_key
)
@receiver(user_logged_in)
@transaction.atomic
def clear_sessions_on_login(sender, request, user, **kwargs):
"""
clear_sessions_on_login
Wrapped in an atomic transaction because of
altering multiple tables and rows in succession.
"""
delete_sessions(user)
create_user_session(request, user)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment