Sessions in Lback Framework

Sessions provide a way to store user-specific data across multiple HTTP requests. In Lback, Database Sessions are used, meaning session data is persistently stored in your database, offering greater flexibility and stability.

1. Session Structure in the Database

Session data is stored in a Session table in your database (typically db.sqlite if you’re using SQLite). This table primarily consists of the following columns:

  • id: A unique identifier for the session (usually a UUID). This is the session_id sent to the browser in the Cookie.

  • user_id: (Optional) The ID of the user associated with this session. This column is dedicated to directly linking a session to a specific user in your users table.

  • data: The most important column. This stores all the actual session data (e.g., shopping cart contents, login status, flash messages). This data is stored as a JSON string (a TEXT type in the database).

  • expires_at: The date and time when the session expires. This date is automatically renewed with each request.

  • created_at: The date and time when the session was first created.

  • updated_at: The date and time of the last update to the session.

2. How Sessions Work in Lback

Session management in Lback relies on two core components:

  • SessionMiddleware: This middleware (located in lback/middlewares/session_middleware.py) is responsible for:
    • Reading the Session ID from a cookie at the beginning of each request.

    • Fetching session data from the database using the SessionManager.

    • Placing an ``AppSession`` object (the session wrapper) into the request context (request.context['session']) for easy access by your views.

    • Saving modified session data back to the database at the end of the request (if changes occurred).

    • Setting or deleting the session cookie in the browser’s response.

  • SessionManager: This class (located in lback/utils/session_manager.py) directly interacts with the database to:
    • Create new sessions.

    • Retrieve existing session data.

    • Update session data.

    • Renew session expiration.

    • Delete sessions.

The Workflow:

  1. When an HTTP request arrives, SQLAlchemyMiddleware first sets up a database session (db_session).

  2. Next, SessionMiddleware inspects the request for a session_id cookie.

  3. If no session_id is found or it’s invalid/expired, it’s treated as a new session, and a new session_id is generated and stored in the database by SessionManager.

  4. If a valid session_id exists, SessionMiddleware retrieves the associated session data from the database.

  5. In either case, an AppSession object (which wraps the session data and associated logic) is initialized and made available via request.context['session'].

  6. Your views and controllers can now interact with request.session.

  7. After the request is processed by your view, and before the response is sent back to the browser, SessionMiddleware saves any changes made to request.session back to the database and updates the session cookie in the response.

3. Session Configuration Options in settings.py

You can customize session behavior by configuring the following settings in your project’s settings.py file:

  • SESSION_TIMEOUT_MINUTES: (Required) Specifies how long a session remains valid (in minutes) if there’s no activity. The session’s expiration is automatically renewed with each request made within this period.

    • Example: SESSION_TIMEOUT_MINUTES = 30 (session expires after 30 minutes of inactivity).

  • SESSION_COOKIE_NAME: (Optional, default is session_id) The name of the cookie used to store the session ID in the user’s browser.

    • Example: SESSION_COOKIE_NAME = 'my_app_session_id'

4. Accessing and Storing Session Data in Views

Once SessionMiddleware makes the AppSession object available in request.context['session'], developers can easily access and manipulate session data within their views (or controllers).

request.session behaves like a dictionary-like object, allowing for straightforward data storage and retrieval.

Examples:

  1. Storing data in the Session:

    # In your View or Controller
    def login_view(request: Request):
        # ... (after successful login credential verification) ...
        user = get_user_by_credentials(request.form)
        if user:
            request.session['user_id'] = user.id
            request.session['username'] = user.username
            request.session['is_authenticated'] = True
            request.session['flash_messages'] = [{'message': 'Welcome back!', 'category': 'success'}]
            # All this data will be automatically saved to the database at the end of the request
            return redirect('/')
        # ...
    
  2. Accessing data from the Session:

    # In your View or Controller
    def profile_view(request: Request):
        user_id = request.session.get('user_id')
        username = request.session.get('username')
    
        if user_id and username:
            # Load user data from the database using user_id
            # ...
            return render_template('profile.html', user_id=user_id, username=username)
        else:
            # User not logged in or data not in session
            request.session['flash_messages'] = [{'message': 'Please log in to view your profile.', 'category': 'warning'}]
            return redirect('/login')
    
    def display_flash_messages(request: Request):
        # Typically called in the base template
        messages = request.session.get('flash_messages', [])
        # After displaying messages, they should be cleared so they don't reappear
        if messages:
            request.session['flash_messages'] = [] # Clear messages after reading them
        return messages
    
  3. Checking if the Session is New:

    if request.session.is_new:
        print("This is a new user session.")
    
  4. Checking if the Session has been Modified:

    if request.session.modified:
        print("Session data has been modified and will be saved to the database.")
    
  5. Deleting Specific Data from the Session:

    # To delete a single item
    if 'item_in_cart' in request.session:
        del request.session['item_in_cart']
    
    # Or clear all current session data while keeping the session itself
    # (This does not delete the Session from the database, only its contents)
    request.session.clear()
    
  6. Deleting the Entire Session (Logout):

    def logout_view(request: Request):
        request.session.delete() # Deletes the session from the database and removes the cookie
        request.session['flash_messages'] = [{'message': 'You have been logged out.', 'category': 'info'}]
        return redirect('/')
    

By following these guidelines, you will be able to effectively manage sessions in your Lback-based applications.