plain.sessions
Database-backed sessions for managing user state across requests.
- Overview
- Basic usage
- Settings
- Session expiration
- Session management
- Admin interface
- Testing
- FAQs
- Installation
Overview
Sessions allow you to store and retrieve arbitrary data on a per-visitor basis, using a session key stored in a cookie. You can use sessions as a dictionary-like object that automatically handles persistence to the database.
Basic usage
In views that inherit from SessionView, you can use self.session like a standard Python dictionary:
from plain.sessions.views import SessionView
class MyView(SessionView):
def get(self):
# Store values in the session
self.session["username"] = "jane"
self.session["cart_items"] = [1, 2, 3]
# Retrieve values from the session
username = self.session.get("username")
cart_items = self.session.get("cart_items", [])
# Check if a key exists
if "username" in self.session:
# User has a session
pass
# Delete values from the session
del self.session["cart_items"]
Outside of views, you can use get_request_session():
from plain.sessions import get_request_session
session = get_request_session(request)
session["key"] = "value"
The session data is automatically saved when you set or delete values. Sessions are stored in the database using the Session model.
Settings
| Setting | Default | Env var |
|---|---|---|
SESSION_COOKIE_NAME |
"sessionid" |
- |
SESSION_COOKIE_AGE |
1209600 (2 weeks) |
- |
SESSION_COOKIE_DOMAIN |
None |
- |
SESSION_COOKIE_SECURE |
True |
- |
SESSION_COOKIE_PATH |
"/" |
- |
SESSION_COOKIE_HTTPONLY |
True |
- |
SESSION_COOKIE_SAMESITE |
"Lax" |
- |
SESSION_SAVE_EVERY_REQUEST |
False |
- |
SESSION_EXPIRE_AT_BROWSER_CLOSE |
False |
- |
See default_settings.py for more details.
Session expiration
Sessions expire SESSION_COOKIE_AGE seconds after they are last saved (not last accessed).
By default (SESSION_SAVE_EVERY_REQUEST = False), sessions are only saved when modified. For authenticated users, this means the expiration timer resets on login/logout but not when just browsing pages. Users will be logged out after SESSION_COOKIE_AGE even if actively using the site.
To extend sessions on every page access, set SESSION_SAVE_EVERY_REQUEST = True. This creates a sliding window where users stay logged in as long as they visit within SESSION_COOKIE_AGE, but increases database writes.
Session management
The SessionStore class provides additional methods for managing sessions.
Flushing sessions
To completely remove the current session data and regenerate the session key:
# In a view with SessionView
self.session.flush()
# Outside a view
from plain.sessions import get_request_session
session = get_request_session(request)
session.flush()
Cycling session keys
To create a new session key while retaining the current session data (useful for security purposes):
# In a view with SessionView
self.session.cycle_key()
# Outside a view
from plain.sessions import get_request_session
session = get_request_session(request)
session.cycle_key()
Checking if session is empty
# In a view with SessionView
if self.session.is_empty():
# No session data exists
pass
# Outside a view
from plain.sessions import get_request_session
session = get_request_session(request)
if session.is_empty():
# No session data exists
pass
Admin interface
You can view and manage sessions in the admin panel under the "Sessions" section. The admin interface allows you to:
- Search sessions by session key
- View session creation and expiration times
- Delete expired or unwanted sessions
The SessionAdmin viewset provides the interface for managing sessions in the admin panel.
Testing
In a test, get_client_session() gives you the session a test client is using, so you can read what a view stored or set something before a request:
from plain.sessions.testing import get_client_session
from plain.testing import Client
def test_cart_is_remembered():
client = Client()
client.post("/cart/add/", form_data={"sku": "A-1"})
session = get_client_session(client)
assert session["cart"] == ["A-1"]
If the client has no session yet, one is created and its cookie is set on the client. To change the session, set the value and call session.save():
session = get_client_session(client)
session["theme"] = "dark"
session.save()
response = client.get("/") # the view sees session["theme"]
FAQs
How do I clear expired sessions?
You can use the built-in ClearExpired chore to delete expired sessions from the database:
plain chores run plain.sessions.chores.ClearExpired
You can schedule this chore to run periodically using plain.worker or your preferred task scheduler.
How do I access the underlying Session model instance?
You can access the database model instance through the model_instance property:
from plain.sessions import get_request_session
session = get_request_session(request)
session_instance = session.model_instance # Returns the Session model or None
Why is my session not being saved?
Sessions are only saved when modified (when you set or delete a value). If you need the session to be saved on every request, set SESSION_SAVE_EVERY_REQUEST = True in your settings.
Installation
Install the plain.sessions package from PyPI:
uv add plain.sessions
Add plain.sessions to your INSTALLED_PACKAGES and include the SessionMiddleware in your middleware:
INSTALLED_PACKAGES = [
# ...
"plain.sessions",
]
MIDDLEWARE = [
# ...
"plain.sessions.middleware.SessionMiddleware",
# ...
]
Sync the database to create the session table:
plain postgres sync
Metadata
Release files for plain.sessions 0.48.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| plain_sessions-0.48.0.tar.gz | 21.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| plain_sessions-0.48.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.5 kB
Release files / plain_sessions-0.48.0.tar.gz
| Download URL | plain_sessions-0.48.0.tar.gz |
|---|---|
| Size | 21.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2dce918f6eec6770a19e6a8ba877f8e433d443b178354695d93913c4bf40a3aa
|
|
BLAKE2b-256 checksum How to use checksums |
5b5351f1c997d7dd36c12087686db1c1a5bac616549a706c1b8b773344738d89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / plain_sessions-0.48.0-py3-none-any.whl
| Download URL | plain_sessions-0.48.0-py3-none-any.whl |
|---|---|
| Size | 24.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1741803a6ef21a4493a8da1935811235707d8758493d01a6e348fb77016f8db
|
|
BLAKE2b-256 checksum How to use checksums |
d53c39cac231cdc13f12d6f7c91a42ff3e273cd8eda4a7c3a959ed1ba05bd7e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|