Bottle.py session with Beaker
Asked Answered
V

1

5

first time questioner here.

I'm currently struggling on how to use Beaker properly using the Bottle micro-framework. Here's the problematic program:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: server.py

import bottle as app
from beaker.middleware import SessionMiddleware

session_options = {
    'session.type': 'file',
    'session.data_dir': './session/',
    'session.auto': True,
}
app_middlware = SessionMiddleware(app.app(), session_options)
app_session = app.request.environ.get('beaker.session')

@app.route('/login')
def login():
    app_session = app.request.environ.get('beaker.session')
    app_session['logged_in'] = True

@app.route('/logout')
def logout():
    app_session = app.request.environ.get('beaker.session')
    if app_session.get('logged_in'):
        app_session['logged_in'] = False
        return 'You are logged out'
    app.redirect('/login')

@app.route('/dashboard')
def dashboard():
    app_session = app.request.environ.get('beaker.session')
    if app_session.get('logged_in'):
        return 'You are logged in'
    app.redirect('/login')

app.debug(True)
app.run(app=app_middlware, reloader=True)

If you noticed, I keep on calling app_session = app.request.environ.get('beaker.session') on every def block so just it will not return an error like: TypeError: 'NoneType' object does not support item assignment --- it seems that Python doesn't recognize variables that is outside its function (correct me if I'm wrong).

And here are the questions:

  1. What should I do to only have one instance of app_session = app.request.environ.get('beaker.session') so it can be available to every def blocks (I really need one instance since it's the same session to be checked and used).
  2. If this is the only way (it's ugly though), then should I just combine all routes that requires a session just so I can achieve the single instance of app_session?

Something like:

@app.route('/<path:re:(login|dashboard|logout)\/?>')
def url(path):
    app_session = app.request.environ.get('beaker.session')
    if 'login' in path:
        app_session['logged_in'] = True
    elif 'logout' in path:
        if app_session.get('logged_in'):
            # app_session.delete() it doesn't seem to work?
            app_session['logged_in'] = False
            return 'You are logged out'
        app.redirect('/login')
    elif 'dashboard' in path:
        if app_session.get('logged_in'):
            return 'You are logged in'
        app.redirect('/login')
Vinyl answered 6/12, 2012 at 1:5 Comment(6)
So what happens when you don't redefine app_session in each view function and just use the one in the global scope?Finesse
It returns an error, like this: File "server.py", line 14, in login app_session['logged_in'] = True TypeError: 'NoneType' object does not support item assignmentVinyl
Take a look at this question: #9248745Finesse
Sorry Blender, but I already did that before I posted the question. And also SessionMiddleware(app, session_options) causes an error, it should be SessionMiddleware(app.app(), session_options).Vinyl
I switched to Flask because of problems like this... Last attempt: try using app_middleware.session instead of app.session and see if that helps.Finesse
Thanks Blender, unfortunately, it only returns a None value. However, +1 for recommending Flask, I will use it later once I finished this Bottle-based web app. ^^,Vinyl
D
26

Using beaker in your bottle application is easy. First, set up your Bottle app:

import bottle
from bottle import request, route, hook
import beaker.middleware

session_opts = {
    'session.type': 'file',
    'session.data_dir': './session/',
    'session.auto': True,
}

app = beaker.middleware.SessionMiddleware(bottle.app(), session_opts)

And later on:

bottle.run(app=app)

With this in place, every time you receive a request, your Beaker session will be available as request.environ['beaker_session']. I usually do something like this for convenience:

@hook('before_request')
def setup_request():
    request.session = request.environ['beaker.session']

This arranges to run setup_request before handling any request; we're using the bottle.request variable (see the earlier import statement), which is a thread-local variable with information about the current request. From this point on, I can just refer to request.session whenever I need it, e.g.:

@route('/')
def index():
    if 'something' in request.session:
       return 'It worked!'

    request.session['something'] = 1
Disturb answered 6/12, 2012 at 1:35 Comment(1)
Thanks larsks! the @hook('before_request') did the trick. :DVinyl

© 2022 - 2024 — McMap. All rights reserved.