Google App Engine - Getting Sessions working with Python 2.7

Steve picture Steve · Oct 5, 2012 · Viewed 10.6k times · Source

First of all, I'm brand new to GAE, so its possible I'm doing this the wrong way - but I've used PHP before and session was how I kept persistent data. I'm using Python 2.7 because that is what I use for all my other Python development - although I'm beginning to wonder if downgrading to 2.5 might be a valid solution, if not an ideal one.

The scenario is that I'm building a proof-of-concept site, and I need to have a 'dummy' login button that simply sets a session variable called 'user' with a value of 'admin'. I then want to check in the navigation template to see if the variable is set, and if so I'll add some extra menu commands. Very simple. (Note: I KNOW this isn't secure, sensible or anything that should be done - the problem is that session is not working, not what I'm doing with it - I'm doing a couple of other things in the code using session - none of them are working when deployed)

It seems there are a few different session libraries for GAE with Python and I tried the one that was most widely recommended in Google searches - gaeutilities, but this caused errors and wouldn't work (I eventually stumbled across this post to explain that its just not compatible with Python 2.7). A little more searching led me to this library from appenginelearn.com which I dropped in and it worked perfectly... until I deployed it - then it just does nothing. I'd love some pointers or advice as to why this might be failing. Here is the relevant code that I'm using:

I put the util library directory from appenginelearn.com in the root of the application directory, then imported Session:

from util.sessions import Session

Then I added the Login and Logout classes:

class LogIn(webapp2.RequestHandler):
    def get(self):
        self.session = Session()
        self.session['user'] = 'admin'
        # Return the user to the page they logged in from
        referer = self.request.environ['HTTP_REFERER'] \
                if 'HTTP_REFERER' in self.request.environ \
                else '/'
        self.redirect(referer)

class LogOut(webapp2.RequestHandler):
    def get(self):
        self.session = Session()
        self.session.delete_item('user')
        self.redirect('/')

And the following (awful) code in the main class (this will be done for all pages in the demo)

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.session = Session()
        logging.info('Main page fired up')
        if 'user' in self.session:
            user = self.session['user']
        else:
            user = None

        template_values = {
            'user': user
            }
        template = jinja_environment.get_template('main.html')
        self.response.out.write(template.render(template_values))

And then this in the HTML template file

  {% if user %}
      <p>Welcome, {{user}}</p>
  {% endif %}

And the errors in the log:

2012-10-04 02:51:28.084 /login 302 143ms 0kb Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4
*ip address removed* - - [04/Oct/2012:02:51:28 -0700] "GET /login HTTP/1.1" 302 136 "*site-removed*" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4" "*site-removed*" ms=144 cpu_ms=0 cpm_usd=0.000015 instance=*instance removed*
**I** 2012-10-04 02:51:28.080
Creating session session-*session number removed*
**E** 2012-10-04 02:51:28.084
Set-Cookie: appengine-simple-session-sid=*session number removed*; Path=/

Answer

Paul Collingwood picture Paul Collingwood · Oct 5, 2012

Have you seen webapp2 sessions? It's all built in and you can get started right away.

https://webapp2.readthedocs.io/en/latest/api/webapp2_extras/sessions.html

This module provides a lightweight but flexible session support for webapp2. It has three built-in backends: secure cookies, memcache and datastore. New backends can be added extending CustomBackendSessionFactory. The session store can provide multiple sessions using different keys, even using different backends in the same request, through the method SessionStore.get_session(). By default it returns a session using the default key from configuration.

import webapp2

from webapp2_extras import sessions

class BaseHandler(webapp2.RequestHandler):
    def dispatch(self):
        # Get a session store for this request.
        self.session_store = sessions.get_store(request=self.request)

        try:
            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)
        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)

    @webapp2.cached_property
    def session(self):
        # Returns a session using the default cookie key.
        return self.session_store.get_session()

# To set a value:
self.session['foo'] = 'bar'

# To get a value:
foo = self.session.get('foo')

Then it's real easy to build a login system around this, seems you've already done it already. And you get to use the datastore and/or memcache with the webapp2 sessions, as preferred.