Last active
August 20, 2021 16:07
-
-
Save aleksihakli/27ddd0bba822ae219f58c170db75281b to your computer and use it in GitHub Desktop.
Django single session
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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