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 | Provenance | Actions |
|---|---|---|---|---|
| plain_sessions-0.48.0.tar.gz | 21.7 kB | Without provenance | Details for plain_sessions-0.48.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| plain_sessions-0.48.0-py3-none-any.whl | Python 3 | none | any | Details for plain_sessions-0.48.0-py3-none-any.whl |
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}
|
Security for plain.sessions 0.48.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.