session not getting stored in database

hi
i have a test that goes like this:

    def test_cart_is_saved_after_sign_up(self, client):
        client.get("/")
        session = client.session
        session_cart = CartSession(session)
        session_cart.add(self.product1, 2)

where client comes from pytest-django

and CartSession is as follows:

class CartSession:
    def __init__(self, session):
        self.session = session
        cart = self.session.get(settings.CART_SESSION_KEY)
        if not cart:
            cart = self.session[settings.CART_SESSION_KEY] = {}
        self.cart: dict[int, dict] = cart

    def save(self):
        self.session.modified = True

    def add(self, product, quantity=1):
        if product.id not in self.cart:
            self.cart[product.id] = {
                "quantity": 0,
                "price": product.price,
                "discount": product.discount,
                "sell_price": product.get_sell_price(),
            }

        self.cart[product.id]["quantity"] += quantity
        self.save()

now when in the test i try to do this:

        print(session.session_key)
        print(SessionStore(session_key=session.session_key).session_key)
        print(session.keys())
        print(SessionStore(session_key=session.session_key).keys())

i get the following result

t3n66de197huhuttxh4qr50vh3u21uwl
t3n66de197huhuttxh4qr50vh3u21uwl
dict_keys(['cart'])
dict_keys([])

as you can see, session_key is the same, but SessionStore doesn’t return any value
i tried Session.objects.get(pk=session.session_key) as well, and it returns empty as well

What are all of your session-related settings?

Is this CartSession object in your Django project or in your test?

hi
no specific settings, just django’s defaults

the class is in my project, I’m testing to see if it works correctly

There are no “defaults” for session support in Django.

Please post all of the session related settings from your settings.py file.

i’m not exactly sure what you mean
i’m using django/django/conf/global_settings.py at main · django/django · GitHub these

haven’t changed anything
i have CART_SESSION_KEY = "cart" which is used in my CartSession, not by django

these are my installed apps and middlewares (i’m using django-classy-settings)

 def INSTALLED_APPS(self):
        return list(
            filter(
                None,
                [
                    "django.contrib.admin",
                    "django.contrib.auth",
                    "django.contrib.contenttypes",
                    "django.contrib.sessions",
                    "django.contrib.messages",
                    "whitenoise.runserver_nostatic" if self.DEBUG else None,
                    "django.contrib.staticfiles",
                    "django.contrib.sites",
                    "django.contrib.sitemaps",
                    "django.contrib.humanize",
                    # debug toolbar
                    "debug_toolbar" if self.DEBUG else None,
                    # browser reload
                    "django_browser_reload" if self.DEBUG else None,
                    # extensions
                    "django_extensions" if self.DEBUG else None,
                    # harlequin
                    "django_harlequin" if self.DEBUG else None,
                    # health check
                    "health_check",
                    "health_check.db",
                    "health_check.cache",
                    "health_check.storage",
                    "health_check.contrib.migrations",
                    "health_check.contrib.psutil",
                    # allauth
                    "allauth",
                    "allauth.account",
                    "allauth.headless",
                    "allauth.socialaccount",
                    "allauth.socialaccount.providers.google",
                    "allauth.usersessions",
                    # local
                    "accounts",
                ],
            )
        )

    def MIDDLEWARE(self):
        return list(
            filter(
                None,
                [
                    "django.middleware.security.SecurityMiddleware",
                    (
                        "whitenoise.middleware.WhiteNoiseMiddleware"
                        if self.DEBUG
                        else None
                    ),
                    "django.contrib.sessions.middleware.SessionMiddleware",
                    "django.middleware.cache.UpdateCacheMiddleware",
                    "django.middleware.locale.LocaleMiddleware",
                    "django.middleware.common.CommonMiddleware",
                    "django.middleware.cache.FetchFromCacheMiddleware",
                    "django.middleware.csrf.CsrfViewMiddleware",
                    "django.contrib.auth.middleware.AuthenticationMiddleware",
                    "django.contrib.messages.middleware.MessageMiddleware",
                    "django.middleware.clickjacking.XFrameOptionsMiddleware",
                    (
                        "debug_toolbar.middleware.DebugToolbarMiddleware"
                        if self.DEBUG
                        else None
                    ),
                    (
                        "django_browser_reload.middleware.BrowserReloadMiddleware"
                        if self.DEBUG
                        else None
                    ),
                    "allauth.account.middleware.AccountMiddleware",
                    "allauth.usersessions.middleware.UserSessionsMiddleware",
                ],
            )
        )

i also have these in my production settings, which aren’t used while testing

    # session settings
    SESSION_COOKIE_SECURE = env.bool("DJANGO_SESSION_COOKIE_SECURE", default=True)
    SESSION_COOKIE_HTTPONLY = env.bool("DJANGO_SESSION_COOKIE_HTTPONLY", default=True)
    SESSION_COOKIE_DOMAIN = env.str("DJANGO_SESSION_COOKIE_DOMAIN", default="localhost")

First, to be clear, you have addressed my question. But to clarify part of what I was asking about, from the docs at How to use sessions | Django documentation | Django

Sessions are implemented via a piece of middleware.

The link your referenced at: django/django/conf/global_settings.py at ef6a83789b310a441237a190a493c9586a4cb260 · django/django · GitHub shows there is no default for middleware, and so sessions aren’t enabled by default.

(As I mentioned at top, you did show where you do have it, so that issue is covered - assuming that your usage of django-classy-settings is correct. I don’t use that package, so I can’t really verify that.)

I’m not sure I’m understanding what you’re trying to demonstrate with those print statements.

Now, regarding the symptoms you are describing, my gut hunch is that your reference to the SessionStore object is giving you a reference to your default database and not the test database - but that’s just complete conjecture.

What do you get if you print(session[‘cart’])?

ah
sorry about that

session["cart"] prints this:
{4: {'quantity': 2, 'price': 346617455, 'discount': 0, 'sell_price': 346617455}}

which is correct

apart from SessionStore, i’ve tried to manually query django.contrib.session.models.Session
which also doesn’t have anything in it

In [1]: from django.test import Client

In [2]: client = Client()

In [3]: from carts.session_handlers import CartSession

In[4]: session = client.session

In [5]: cart = CartSession(session)

In [6]: from model_bakery import baker

In [7]: product1 = baker.make("products.Product")

In [8]: cart.add(product1, 2)

In [9]: s = SessionStore(session_key=session.session_key)

In [10]: s.keys()
Out[10]: dict_keys([])

In [11]: session.keys()
Out[11]: dict_keys(['cart'])

also, in the shell, outside of the testing env, the same thing happens

I don’t expect the data to be there after the test function has finished, because database updates in a view are made in a transaction which is rolled back after the test has been completed.

Likewise, in your manual work in the shell, I don’t think you’re saving the session data to the database. (That’s a function normally provided by the middleware. If you’re not going through the middleware, then I believe you would need to call save on the session object for it to be written.)

ahh i did need to call save() on it

but in my defense, the prints i posted were all in the test case, so they would have access to the test data :upside_down_face:
but i still had to call save()

thanks!!, and sorry for the mess :folded_hands:

“Have access to” - yes. However, what I don’t know is whether the reference to the SessionStore object directly is going to result in that object accessing the default database or the test database; or even if it is accessing the test database, whether such access is going to be in the context of the transaction being used for that view. (Again, I don’t know this one way or the other, but it’s the question I would want to find the answer to.)

calling .save() as you suggested solved the issue
SessionStore does use the test database

my problem was that i thought using the session from the test client wouldn’t require me to call .save(), and auto-save would happen.
which was wrong

thanks again for the help :raising_hands: