简体   繁体   中英

Avoiding Python globals in Google App/Cloud Engine

There must be a better and more Pythonic way to do this. I have created a small GAE app that demonstrates my problem (and ignorance). Here you enter your name on an entry page. The app then greets you and increments a number with every click. Works great -- until someone else uses the app at the same time, at which point one user inherits the other's name.

Is this because the name is stored in a_state , a global (singleton) object declared at the bottom? If so, how can I make sure all users keep their own names? Thanks in advance!

import webapp2

class AState:
    my_name = "Foo"
    a_number = 42

class GetName(webapp2.RequestHandler):
    def post(self):
        the_state.my_name = self.request.get('the_name')
        self.redirect('/main')

    def get(self):
        self.response.write("""
        <html><body><form action="/" method="post">
            Type your name <input type="text" name="the_name">
            <input type="submit" value="Continue">
        </form></body></html>
        """)


class Main(webapp2.RequestHandler):
    def get(self):
        the_state.a_number += 1
        self.response.write("""
        <html><body><form action="/main" method="get">
        Hello, %s! The number is %d. 
        <input type="submit" value="Keep going">
        </form></body></html>
        """ % (the_state.my_name, the_state.a_number))


app = webapp2.WSGIApplication([
    ('/', GetName),
    ('/main', Main)
], debug=True)

the_state = AState()

Note: In the real app, I'm using ndb to store (successfully!) information that should be shared among all users. My problem is with this more ephemeral, user-specific info.

So is the right solution to bite the bullet and store even this stuff in the datastore?

From my old php days, I should have known that the term I was looking for was SESSION. Hooray -- webapp2 has sessions too. Here is complete working code; it may help someone trying to get a minimal program working.

The key is to define a new handler for requests, BaseHandler . You will also have to set a configuration. See this webapp2 documentation .

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()


class GetName(BaseHandler):  # NB: see how we're now inheriting from BaseHandler?
    def post(self):
        self.session['my_name'] = self.request.get('the_name')
        self.session['a_number'] = 42  # NB: setting a session variable
        self.redirect('/main')

    def get(self):
        self.response.write("""
        <html><body><form action="/" method="post">
            Type your name <input type="text" name="the_name">
            <input type="submit" value="Continue">
        </form></body></html>
        """)


class Main(BaseHandler):
    def get(self):
        t_num = self.session.get('a_number') # NB: retrieving a session variable
        t_num += 1
        self.session['a_number'] = t_num

        self.response.write("""
        <html><body><form action="/main" method="get">
        Hello, %s! The number is %d. <input type="submit" value="Keep going">
        </form></body></html>
        """ % (self.session.get('my_name'), t_num))

config = {}
config['webapp2_extras.sessions'] = {
    'secret_key': 'H81%6_(^&k2&)!'     # or some other miscellaneous string
}

app = webapp2.WSGIApplication([
    ('/', GetName),
    ('/main', Main)
], debug=True, config=config)   # NB the config gets added

def main():
    app.run()

if __name__ == '__main__':
    main()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM