pythongoogle-app-enginewebapp2webobgae-python27

Set an attribute on a request before it's handled


My App Engine application has a custom user model. This model is accessed frequently in the application code. I would like to simplify the code by injecting a model instance into each authenticated request before the request is handled (similar to the process_request method of Django middleware classes).

I am using the App Engine Python2.7 standard runtime with webapp2 as the framework.

I tried creating a WSGI middleware callable that modified the WSGI environ dictionary and defined a webapp_add_wsgi_middleware function appengine_config.py to add the middleware, but the middleware did not run until after the request had been processed by the app.

How can I modify the request before it's handled by the application?


Solution

  • The solution I found was to create a subclass of webapp2.WSGIApplication and have that modify the environ dictionary before calling the superclass to run the app. To set the instance as an attribute of the request, rather than having to access it via Request.environ, I added it to the environ's 'webob.adhoc_attrs' value. This is because webapp2's Request class inherits from webob's, which in turn inherits from a mixin class that manages attribute access.

    Here's an example application that sets an attribute on all requests:

    import webapp2
    
    
    class Handler(webapp2.RequestHandler):
    
        def get(self):
            try:
                foo = self.request.foo
            except AttributeError:
                foo = 'Default'
            self.response.write('Hello %s' % foo)
    
    
    routes = [('/', Handler)]
    
    
    class MyWSGIApplication(webapp2.WSGIApplication):
    
        def __call__(self, environ, start_response):
            adhoc_attrs = {'foo': 'Foo'}
            if 'webob.adhoc_attrs' in environ:
                environ['webob.adhoc_attrs'].update(adhoc_attrs)
            else:
                environ['webob.adhoc_attrs'] = adhoc_attrs
            return super(MyWSGIApplication, self).__call__(environ, start_response)
    
    
    app = MyWSGIApplication(routes)