How can I get Session from the request in the middleware?

Greetings Everyone

So this is my middleware code

from .models import UserSession, Session
from apps.core.utils import get_user_agent, get_user_ip


class UserSessionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        print("GOT IT")
        if request.user.is_authenticated:
            context = {
                "user": request.user,
                "session": request.session,
                "ip_address": get_user_ip(request),
                "user_agent": get_user_agent(request),
            }
            UserSession.objects.get_or_create(**context)


        return self.get_response(request)

IDK why this is not working

Here is the traceback

Environment:


Request Method: GET
Request URL: http://localhost:8000/admin/

Django Version: 4.2.4
Python Version: 3.10.9
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'django.contrib.redirects',
 'apps.core.apps.CoreConfig',
 'apps.account.apps.AccountConfig',
 'apps.forum.apps.ForumConfig',
 'apps.notification.apps.NotificationConfig',
 'django_cleanup.apps.CleanupConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
 'apps.account.middleware.UserSessionMiddleware']



Traceback (most recent call last):
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\query.py", line 916, in get_or_create
    return self.get(**kwargs), False
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\query.py", line 637, in get
    raise self.model.DoesNotExist(

During handling of the above exception (UserSession matching query does not exist.), another exception occurred:
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "E:\Documents\Projects\Fern\apps\account\middleware.py", line 18, in __call__
    UserSession.objects.get_or_create(**context)
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\query.py", line 923, in get_or_create
    return self.create(**params), True
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\query.py", line 656, in create
    obj = self.model(**kwargs)
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\base.py", line 543, in __init__
    _setattr(self, field.name, rel_obj)
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 369, in __set__
    super().__set__(instance, value)
  File "E:\Documents\Projects\Fern\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 266, in __set__
    raise ValueError(

Exception Type: ValueError at /admin/
Exception Value: Cannot assign "<django.contrib.sessions.backends.db.SessionStore object at 0x000001BA191D3CD0>": "UserSession.session" must be a "Session" instance.

The error message is pretty clear.

request.session is not the Session instance from the databse : it’s an object corresponding to a subclass of django.contrib.sessions.backends.base.SessionBase (which defines a common API to access session data). The real class of the object depends on the session engine used: when you use the database backend, its an object of the class django.contrib.sessions.backend.db.SessionStore. If you look at definition of this class in django sources, you will see that it does not have an attribute that hold the corresponding Session object (such object is only retrieved on session load, and is created/updated on session save).

I assume that the Session class linked to your UserSession object comes from django.contrib.sessions.models, despite you import it from your own .models module.

Session object primary key is the session_key you can find on the request.session object. So you have two ways link to the session in context:

  1. "session": Session.objects.get(session_key=request.session.session_key)

  2. "session_id": request.session.session_key

The second solution is better as it avoids an unnecessary call to the database.

1 Like

Great :smiley:

Thanks for your help